Velocity Reviews - Computer Hardware Reviews

Velocity Reviews > Newsgroups > Programming > Ruby > Class variables, instance variables, singleton; Ruby v. C++

Reply
Thread Tools

Class variables, instance variables, singleton; Ruby v. C++

 
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-28-2009
Ralph Shnelvar wrote:
[...]
> Let me flesh out my questions/comments about this paragraph so that you
> and
> others have something specific to answer. Let's call the classed F &
> G.
>
> (1) OK, classes are (i) objects;


Right.

> (ii) are executable code.


Wrong. Class *definitions* are executable code.

>
>
> (2) If I do the following
> class F
> end
> f = F.new
> F.class # class
> f.class # F
> this makes sense to me.
>
> What (relevant and important conceptually) messages (other than "new")
> can I send to a class?


See the documentation for class Class.

> But see (3), below.
>
>
>
> (3)
> class F
> def sub1
> @@x = 1
> end
> end
>
> class G
> self.sub1
> @@x=2
> end
> end
>
> # Why? Didn't the interpreter "see" @@x in class F?
> F.class_variables # []


Probably not, since you haven't called the function yet!

>
> # makes sense
> G.class_variables # ["@@x"]


I'm actually rather surprised by this.

>
> f = F.new
>
> # Why? Shouldn't the method inherit from the class?
> f.class_variables # undefined method


No! class_variables is a class method of F. Instances do not get
access to their class' class methods, because they don't inherit from
the Class object in the conventional sense. The Class object is a
little bit like a JavaScript prototype, if that helps.

If it doesn't...well, I don't know what to say. If you're really as
good a C++ programmer as you claim to be, then you should be having no
trouble at all with the difference between class and instance methods.

>
> f.sub1 # 1
>
> # makes sense. class variable now explicitly executed
> F.class_variables # ["@@x"]
>
> # How to use class_variable_get if the method is private???
> F.class_variable_get(:@@x) # error private method!
>


Just don't. You're not meant to be getting at class variables from
outside the class. Use an accessor function if you need it.

(There is a way to call private methods from outside, but I will leave
you to find it out on your own. It's not generally a good thing, and
I'm not going to hand you a dangerous tool until you understand when not
to use it.)

>
>
> OK, that should do it for now.


Best,
--
Marnen Laibow-Koser
http://www.marnen.org
http://www.velocityreviews.com/forums/(E-Mail Removed)
--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
 
 
 
Ralph Shnelvar
Guest
Posts: n/a
 
      11-28-2009
>> (2) If I do the following
>> class F
>> end
>> f = F.new
>> F.class # class
>> f.class # F
>> this makes sense to me.
>>
>> What (relevant and important conceptually) messages (other than "new")
>> can I send to a class?


MLK> See the documentation for class Class.

>> But see (3), below.
>>
>>
>>
>> (3)
>> class F
>> def sub1
>> @@x = 1
>> end
>> end
>>
>> class G
>> self.sub1
>> @@x=2
>> end
>> end
>>
>> # Why? Didn't the interpreter "see" @@x in class F?
>> F.class_variables # []


MLK> Probably not, since you haven't called the function yet!

Didn't the interpreter parse it?

If I do
class X
def y
xyzzy = 3++
end
end

then the interpreter/parser will complain immediately that there was a
syntax error even though the function method y was not executed.

>>
>> # makes sense
>> G.class_variables # ["@@x"]


MLK> I'm actually rather surprised by this.

I made a mistake. I apologize.
class G
def self.sub1
@@x=2
end
end

G.class_variables # []

(I must have run the function accidentally. Sorry.)

>>
>> f = F.new
>>
>> # Why? Shouldn't the method inherit from the class?
>> f.class_variables # undefined method


MLK> No! class_variables is a class method of F. Instances do not get
MLK> access to their class' class methods, because they don't inherit from
MLK> the Class object in the conventional sense. The Class object is a
MLK> little bit like a JavaScript prototype, if that helps.

MLK> If it doesn't...well, I don't know what to say. If you're really as
MLK> good a C++ programmer as you claim to be, then you should be having no
MLK> trouble at all with the difference between class and instance methods.

In C++, instances have access to the static variables and functions of
the class.

They don't inherit it ... but merely have access to it as if they
inherited it.

>>
>> f.sub1 # 1
>>
>> # makes sense. class variable now explicitly executed
>> F.class_variables # ["@@x"]
>>
>> # How to use class_variable_get if the method is private???
>> F.class_variable_get(:@@x) # error private method!
>>


MLK> Just don't. You're not meant to be getting at class variables from
MLK> outside the class. Use an accessor function if you need it.

MLK> (There is a way to call private methods from outside, but I will leave
MLK> you to find it out on your own. It's not generally a good thing, and
MLK> I'm not going to hand you a dangerous tool until you understand when not
MLK> to use it.)

So ... when _can_ I use class_variable_get ???



 
Reply With Quote
 
 
 
 
Rick DeNatale
Guest
Posts: n/a
 
      11-28-2009
On Sat, Nov 28, 2009 at 8:00 AM, Ralph Shnelvar <(E-Mail Removed)> wrote:
> DAB> And of course this is one of the (many) problems with class variable=

s:
> DAB> they make obscure the otherwise rather simple notion that classes ca=

n
> DAB> have instance variables because classes are objects and any object c=

an
> DAB> have instance variables.
>
> David ... this may be the higher-level gestalt that I was missing. =A0It
> sure sounds like it.
>
> Let me flesh out my questions/comments about this paragraph so that you a=

nd
> others have something specific to answer. =A0Let's call the classed =A0F =

&
> G.
>
> (1) OK, classes are (i) objects; (ii) are executable code.



I wouldn't say that classes are executable code. However the
difference between Ruby and C++ here is that in C++ a class is really
just a C Struct definition with new features like virtual member
functions and inheritance. It's a static compile time construct.

In Ruby on the other hand, classes are defined at run time as code is
executed, and the stuff inside a class definition is executable code.

Another related difference is that in C++ the class describes which
instance variables are present in every instance of that class by
virtue of the instance variables (members) being statically declared.

In Ruby an object gets instance variables one by one only when it
executes a method which sets the instance variable. Since classes are
objects this applies to classes as well.

A primary purpose of a class is to collect method implementations
which will be part of the repertoire of instances of that class.

So for example

class A
# At this point the class has no class instance variables
@class_instance_variable1 =3D 42 # This statement is executed when
the class def is, so
# after this A
has a class instance variable

# The following defines a method which will be in the repertoire
of instances of A or any
# of its subclasses
def some_method
@instance_var =3D "Hello"
end

# The self. makes the following a method of the class A. We
call this a class method
# it will also be in the repertoire of any class objects which
subclass A (but not their instances)
def self.a_class_method
@class_instance_variable2 =3D [1, 2, 3]
end
end

a =3D A.new
# At this point of execution:
#
# The class A has ONE class instance variable @class_instance_variable1
#
# a, which is an instance of A, has NO instance variables

a.some_method

# And now a has an instance variable named @instance_var

A.a_class_method
# And now A has another class instance variable @class_instance_variable2



> (2) If I do the following
> =A0 =A0 =A0class F
> =A0 =A0 =A0end
> =A0 =A0 =A0f =3D F.new
> =A0 =A0 =A0F.class =A0# class
> =A0 =A0 =A0f.class =A0# F
> this makes sense to me.
>
> What (relevant and important conceptually) messages (other than "new")
> can I send to a class? =A0But see (3), below.


Well like any object the answer to that depends on the class. All
classes are instances of Class, which defines three methods, only two
of which are normally called by user code.

Class#allocate which actually allocates the storage for a new
instance, this is rarely if ever overriden or called directly
Class#new which calls allocate to get a new instance and then calls
intialialize on the new instance passing any arguments along. This is
called often but rarely overridden.
Class#superclass which returns the superclass of the class, again
called but almost never overridden.

In addition Class is a subclass of Module, and inherits from module
the ability to collect methods and to serve as a nested namespace. So
every class object has the instance methods defined in Module as part
of its repertoire, I'll leave you to look these up.

And of course the instance methods defined in Object and the module
Kernel (which is included by Object) are part of the repertoire of
very Object and therefore every object which happens to be a class.

Some Ruby standard library classes like Array, Dir, File and others
define additional class methods specific to the class and its
subclasses.


> (3)
> =A0 =A0class F
> =A0 =A0 =A0def sub1
> =A0 =A0 =A0 =A0@@x =3D 1
> =A0 =A0 =A0end
> =A0 =A0end
>
> =A0 =A0class G
> =A0 =A0 =A0self.sub1
> =A0 =A0 =A0 =A0@@x=3D2
> =A0 =A0 =A0end
> =A0 =A0end
>
> =A0 =A0# Why? =A0Didn't the interpreter "see" @@x in class F?
> =A0 =A0F.class_variables =A0# []


See my explanation above. In this regard class variables like
instance variables

F doesn't have any class variables because the sub1 method hasn't been exec=
uted.

G does because you execute sub1 inside its class definition code. I
assume that you actually defined G as a subclass of F or you would
have gotten an undefined sub1 method error.

And you have invalid syntax in that snippet because there's an extra end

class G
self.sub1
@@x =3D 2
end # this ends the class def which consists of two
end

> =A0 =A0# makes sense
> =A0 =A0G.class_variables =A0# ["@@x"]
>
> =A0 =A0f =3D F.new
>
> =A0 =A0# Why? =A0Shouldn't the method inherit from the class?
> =A0 =A0f.class_variables =A0# undefined method


Because f is an instance of F, and is not a class, class_variables is
a method defined in Module, not Object or kernel
>
> =A0 =A0f.sub1 =A0# 1
>
> =A0 =A0# makes sense. =A0class variable now explicitly executed
> =A0 =A0F.class_variables # ["@@x"]
>
> =A0 =A0# How to use class_variable_get if the method is private???
> =A0 =A0F.class_variable_get(:@@x) =A0# error private method!


F.send(:class_variable_get, :@@x)


As others have pointed out class variables are a pretty wonky area of
Ruby. In Ruby 1.8 if G is a actually a subclass of F, then whether or
not @@x is the same instance variable for both depends in some cases
on whether or not F got its instance variable before G did or not.

When a class variable is initialized Ruby 1.8 looks through the chain
of superclasses to see if a class variable with that name already
exists, and if so uses that definition. If not it defines it for the
current class. Ruby 1.9 changed that so that now class variables are
no longer shared with subclasses.


Now it may seem hard or harsh, but I'd recommend that you try to
forget what you know about C++ when learning Ruby.

Although C++ and Ruby are both said to be object-oriented, they come
from two very different views of what that means. C++ is the epitome
of what Ralph Johnson calls the "Software Engineering" school, where
objects are seen as an extension of abstract data types. Ruby is of
what he calls the "Mystical" school where objects are seen as entities
which encapsulate both the data representation and the methods which
operate on the data, and which interact with other objects only by
message invocation of methods, looked up by name at runtime. Java is
influenced by the SE school, but is more dynamic in other regards.
Other mystical languages include Smalltalk, Self, and JavaScript
although JavaScript is not fundamentally OO.

--=20
Rick DeNatale

Blog: http://talklikeaduck.denhaven2.com/
Twitter: http://twitter.com/RickDeNatale
WWR: http://www.workingwithrails.com/pers...-rick-denatale
LinkedIn: http://www.linkedin.com/in/rickdenatale

 
Reply With Quote
 
David Masover
Guest
Posts: n/a
 
      11-28-2009
On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote:

> >> But see (3), below.
> >>
> >>
> >>
> >> (3)
> >> class F
> >> def sub1
> >> @@x = 1
> >> end
> >> end
> >>
> >> class G
> >> self.sub1
> >> @@x=2
> >> end
> >> end
> >>
> >> # Why? Didn't the interpreter "see" @@x in class F?
> >> F.class_variables # []

>
> MLK> Probably not, since you haven't called the function yet!
>
> Didn't the interpreter parse it?
>
> If I do
> class X
> def y
> xyzzy = 3++
> end
> end
>
> then the interpreter/parser will complain immediately that there was a
> syntax error even though the function method y was not executed.


Yes, syntax errors are caught immediately by parsing. But think of instance
variables as a hash associated with the object and it might be more clear. For
example, if you did this:

SomeHash = {}
def foo
SomeHash[] = :y
end

Would you expect SomeHash[] to exist just because you defined that method?

Now, I don't know whether instance variables are _actually_ implemented as a
hash. It might well be something much more efficient, but it behaves like a
hash, so that makes sense.

Also, consider: The method in question may _never_ be called. Why should Ruby
bother to create a variable that may never be used? That would be just as
foolish as implying that SomeHash[] exists before foo is called in my
example above. Sure, you could create it and set it to nil, but that'd be
pointless.

> In C++, instances have access to the static variables and functions of
> the class.
>
> They don't inherit it ... but merely have access to it as if they
> inherited it.


Instances indeed get access to class variables associated with that instance,
but again, class variables behave weirdly. But here's a quick example to help
clarify things:

SomeClass.new

Would you expect an object created that way to have a 'new' method of its own?
That is, would this make any sense:

SomeClass.new.new

Similarly, do the methods available at class creation time make any sense in
an object? For example, when creating a class:

class Foo
attr_accessor :bar
end

You might think attr_accessor is a keyword. It isn't, it's just a method on
Class, so it's a class method on Foo.

There is no proper analog to "static functions" in C++, by the way -- they're
just methods on the class. But again, they aren't included into the instance
-- you access them on the class, just like you would with any other object.

So let me return to some simple examples that I hope make sense. Let's create
a counter for the number of instances that have been created.

class Foo
def self.count
@count
end
def self.increment_count
@count ||= 0
@count += 1
end
end

This should be easy to understand. (If it's not, pretend I defined them
without self, and see if they make sense.)

Now, go define them, and play with them in irb. You wouldn't create any
instances of Foo yet, but you can do things like this:

Foo.count
Foo.increment_count
Foo.count
Foo.increment_count
Foo.increment_count
Foo.count

Go try that in irb, and see if the result makes sense.

Now let's move on. Keep the same class above, but add this -- if you're in the
same irb session, you can just re-open the class:

class Foo
def initialize
Foo.increment_count
end
end

Now our counter should work as expected:

Foo.count
f = Foo.new
Foo.count

It won't tell you how many Foo objects actually exist. It's more a count of
how many have ever been created.

Also, if you understand this so far, go back to my earlier example that was
"way over your head" -- see if it makes sense. I'll give you an example -- if
you have a variable f, which is an instance of class Foo, what is f.class?

And if you're inside the initialize method of f, what is self? And what is
self.class?

> MLK> (There is a way to call private methods from outside, but I will leave
> MLK> you to find it out on your own. It's not generally a good thing, and
> MLK> I'm not going to hand you a dangerous tool until you understand when
> not MLK> to use it.)
>
> So ... when _can_ I use class_variable_get ???


You can use it whenever you want. When _should_ you use it?

Like instance_variable_get, it's designed for metaprogramming -- that is, when
you're trying to access a variable, but its name is dynamic.

I'll give you an example of when instance_variable_get might be used. Remember
attr_reader? (If not, look it up...) Now, for speed, attr_reader is defined
in C, but it can be defined in Ruby. Here's the obvious 'eval' solution:

class Module
def attr_reader *names
names.each do |name|
eval "def #{name}; @#{name}; end"
end
end
end

But there are many reasons I dislike eval. Here's the solution I'd prefer:

class Module
def attr_reader *names
names.each do |name|
var_name = :"@#{name}"
define_method name do
instance_variable_get var_name
end
end
end
end

I don't expect you to follow every detail here. The use of define_method is an
advanced topic already. Hopefully, though, the fact that you already know how
to use attr_reader should give you an idea of how that works.

Also, I don't really expect you to need any of this yet -- attr_reader,
attr_writer, and attr_accessor should already do everything you need.

 
Reply With Quote
 
Ralph Shnelvar
Guest
Posts: n/a
 
      11-28-2009
Rick,

I know I am top-posting but ...

This has been super-helpful. It presents a helicopter view of what
was, uh, mystifying me.

Many, many, thanks.

Ralph


Saturday, November 28, 2009, 7:46:26 AM, you wrote:

RD> On Sat, Nov 28, 2009 at 8:00 AM, Ralph Shnelvar <(E-Mail Removed)> wrote:
>> DAB> And of course this is one of the (many) problems with class variables:
>> DAB> they make obscure the otherwise rather simple notion that classes can
>> DAB> have instance variables because classes are objects and any object can
>> DAB> have instance variables.
>>
>> David ... this may be the higher-level gestalt that I was missing. *It
>> sure sounds like it.
>>
>> Let me flesh out my questions/comments about this paragraph so that you and
>> others have something specific to answer. *Let's call the classed *F &
>> G.
>>
>> (1) OK, classes are (i) objects; (ii) are executable code.



RD> I wouldn't say that classes are executable code. However the
RD> difference between Ruby and C++ here is that in C++ a class is really
RD> just a C Struct definition with new features like virtual member
RD> functions and inheritance. It's a static compile time construct.

RD> In Ruby on the other hand, classes are defined at run time as code is
RD> executed, and the stuff inside a class definition is executable code.

RD> Another related difference is that in C++ the class describes which
RD> instance variables are present in every instance of that class by
RD> virtue of the instance variables (members) being statically declared.

RD> In Ruby an object gets instance variables one by one only when it
RD> executes a method which sets the instance variable. Since classes are
RD> objects this applies to classes as well.

RD> A primary purpose of a class is to collect method implementations
RD> which will be part of the repertoire of instances of that class.

RD> So for example

RD> class A
RD> # At this point the class has no class instance variables
RD> @class_instance_variable1 = 42 # This statement is executed when
RD> the class def is, so
RD> # after this A
RD> has a class instance variable

RD> # The following defines a method which will be in the repertoire
RD> of instances of A or any
RD> # of its subclasses
RD> def some_method
RD> @instance_var = "Hello"
RD> end

RD> # The self. makes the following a method of the class A. We
RD> call this a class method
RD> # it will also be in the repertoire of any class objects which
RD> subclass A (but not their instances)
RD> def self.a_class_method
RD> @class_instance_variable2 = [1, 2, 3]
RD> end
RD> end

RD> a = A.new
RD> # At this point of execution:
RD> #
RD> # The class A has ONE class instance variable @class_instance_variable1
RD> #
RD> # a, which is an instance of A, has NO instance variables

RD> a.some_method

RD> # And now a has an instance variable named @instance_var

RD> A.a_class_method
RD> # And now A has another class instance variable @class_instance_variable2



>> (2) If I do the following
>> * * *class F
>> * * *end
>> * * *f = F.new
>> * * *F.class *# class
>> * * *f.class *# F
>> this makes sense to me.
>>
>> What (relevant and important conceptually) messages (other than "new")
>> can I send to a class? *But see (3), below.


RD> Well like any object the answer to that depends on the class. All
RD> classes are instances of Class, which defines three methods, only two
RD> of which are normally called by user code.

RD> Class#allocate which actually allocates the storage for a new
RD> instance, this is rarely if ever overriden or called directly
RD> Class#new which calls allocate to get a new instance and then calls
RD> intialialize on the new instance passing any arguments along. This is
RD> called often but rarely overridden.
RD> Class#superclass which returns the superclass of the class, again
RD> called but almost never overridden.

RD> In addition Class is a subclass of Module, and inherits from module
RD> the ability to collect methods and to serve as a nested namespace. So
RD> every class object has the instance methods defined in Module as part
RD> of its repertoire, I'll leave you to look these up.

RD> And of course the instance methods defined in Object and the module
RD> Kernel (which is included by Object) are part of the repertoire of
RD> very Object and therefore every object which happens to be a class.

RD> Some Ruby standard library classes like Array, Dir, File and others
RD> define additional class methods specific to the class and its
RD> subclasses.


>> (3)
>> * *class F
>> * * *def sub1
>> * * * *@@x = 1
>> * * *end
>> * *end
>>
>> * *class G
>> * * *self.sub1
>> * * * *@@x=2
>> * * *end
>> * *end
>>
>> * *# Why? *Didn't the interpreter "see" @@x in class F?
>> * *F.class_variables *# []


RD> See my explanation above. In this regard class variables like
RD> instance variables

RD> F doesn't have any class variables because the sub1 method hasn't been executed.

RD> G does because you execute sub1 inside its class definition code. I
RD> assume that you actually defined G as a subclass of F or you would
RD> have gotten an undefined sub1 method error.

RD> And you have invalid syntax in that snippet because there's an extra end

RD> class G
RD> self.sub1
RD> @@x = 2
RD> end # this ends the class def which consists of two
RD> end

>> * *# makes sense
>> * *G.class_variables *# ["@@x"]
>>
>> * *f = F.new
>>
>> * *# Why? *Shouldn't the method inherit from the class?
>> * *f.class_variables *# undefined method


RD> Because f is an instance of F, and is not a class, class_variables is
RD> a method defined in Module, not Object or kernel
>>
>> * *f.sub1 *# 1
>>
>> * *# makes sense. *class variable now explicitly executed
>> * *F.class_variables # ["@@x"]
>>
>> * *# How to use class_variable_get if the method is private???
>> * *F.class_variable_get(:@@x) *# error private method!


RD> F.send(:class_variable_get, :@@x)


RD> As others have pointed out class variables are a pretty wonky area of
RD> Ruby. In Ruby 1.8 if G is a actually a subclass of F, then whether or
RD> not @@x is the same instance variable for both depends in some cases
RD> on whether or not F got its instance variable before G did or not.

RD> When a class variable is initialized Ruby 1.8 looks through the chain
RD> of superclasses to see if a class variable with that name already
RD> exists, and if so uses that definition. If not it defines it for the
RD> current class. Ruby 1.9 changed that so that now class variables are
RD> no longer shared with subclasses.


RD> Now it may seem hard or harsh, but I'd recommend that you try to
RD> forget what you know about C++ when learning Ruby.

RD> Although C++ and Ruby are both said to be object-oriented, they come
RD> from two very different views of what that means. C++ is the epitome
RD> of what Ralph Johnson calls the "Software Engineering" school, where
RD> objects are seen as an extension of abstract data types. Ruby is of
RD> what he calls the "Mystical" school where objects are seen as entities
RD> which encapsulate both the data representation and the methods which
RD> operate on the data, and which interact with other objects only by
RD> message invocation of methods, looked up by name at runtime. Java is
RD> influenced by the SE school, but is more dynamic in other regards.
RD> Other mystical languages include Smalltalk, Self, and JavaScript
RD> although JavaScript is not fundamentally OO.




--
Best regards,
Ralph (E-Mail Removed)


 
Reply With Quote
 
Ralph Shnelvar
Guest
Posts: n/a
 
      11-28-2009
DM> On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote:

>> >> But see (3), below.
>> >>
>> >>
>> >>
>> >> (3)
>> >> class F
>> >> def sub1
>> >> @@x = 1
>> >> end
>> >> end
>> >>
>> >> class G
>> >> self.sub1
>> >> @@x=2
>> >> end
>> >> end
>> >>
>> >> # Why? Didn't the interpreter "see" @@x in class F?
>> >> F.class_variables # []

>>
>> MLK> Probably not, since you haven't called the function yet!
>>
>> Didn't the interpreter parse it?
>>
>> If I do
>> class X
>> def y
>> xyzzy = 3++
>> end
>> end
>>
>> then the interpreter/parser will complain immediately that there was a
>> syntax error even though the function method y was not executed.


DM> Yes, syntax errors are caught immediately by parsing. But think of instance
DM> variables as a hash associated with the object and it might be more clear. For
DM> example, if you did this:

DM> SomeHash = {}
DM> def foo
DM> SomeHash[] = :y
DM> end

DM> Would you expect SomeHash[] to exist just because you defined that method?

DM> Now, I don't know whether instance variables are _actually_ implemented as a
DM> hash. It might well be something much more efficient, but it behaves like a
DM> hash, so that makes sense.

DM> Also, consider: The method in question may _never_ be called. Why should Ruby
DM> bother to create a variable that may never be used? That would be just as
DM> foolish as implying that SomeHash[] exists before foo is called in my
DM> example above. Sure, you could create it and set it to nil, but that'd be
DM> pointless.

>> In C++, instances have access to the static variables and functions of
>> the class.
>>
>> They don't inherit it ... but merely have access to it as if they
>> inherited it.


DM> Instances indeed get access to class variables associated with that instance,
DM> but again, class variables behave weirdly. But here's a quick example to help
DM> clarify things:

DM> SomeClass.new

DM> Would you expect an object created that way to have a 'new' method of its own?
DM> That is, would this make any sense:

DM> SomeClass.new.new

DM> Similarly, do the methods available at class creation time make any sense in
DM> an object? For example, when creating a class:

DM> class Foo
DM> attr_accessor :bar
DM> end

DM> You might think attr_accessor is a keyword. It isn't, it's just a method on
DM> Class, so it's a class method on Foo.

DM> There is no proper analog to "static functions" in C++, by the way -- they're
DM> just methods on the class. But again, they aren't included into the instance
DM> -- you access them on the class, just like you would with any other object.

DM> So let me return to some simple examples that I hope make sense. Let's create
DM> a counter for the number of instances that have been created.

DM> class Foo
DM> def self.count
DM> @count
DM> end
DM> def self.increment_count
DM> @count ||= 0
DM> @count += 1
DM> end
DM> end

DM> This should be easy to understand. (If it's not, pretend I defined them
DM> without self, and see if they make sense.)

DM> Now, go define them, and play with them in irb. You wouldn't create any
DM> instances of Foo yet, but you can do things like this:

DM> Foo.count
DM> Foo.increment_count
DM> Foo.count
DM> Foo.increment_count
DM> Foo.increment_count
DM> Foo.count

DM> Go try that in irb, and see if the result makes sense.

DM> Now let's move on. Keep the same class above, but add this -- if you're in the
DM> same irb session, you can just re-open the class:

DM> class Foo
DM> def initialize
DM> Foo.increment_count
DM> end
DM> end

DM> Now our counter should work as expected:

DM> Foo.count
DM> f = Foo.new
DM> Foo.count

DM> It won't tell you how many Foo objects actually exist. It's more a count of
DM> how many have ever been created.

Cool.

Is there a way to tell how many instances actually exist? Is there
anything like a destructor for class instances? Just curious.

DM> Also, if you understand this so far, go back to my earlier example that was
DM> "way over your head" -- see if it makes sense. I'll give you an example -- if
DM> you have a variable f, which is an instance of class Foo, what is f.class?

DM> And if you're inside the initialize method of f, what is self? And what is
DM> self.class?

>> MLK> (There is a way to call private methods from outside, but I will leave
>> MLK> you to find it out on your own. It's not generally a good thing, and
>> MLK> I'm not going to hand you a dangerous tool until you understand when
>> not MLK> to use it.)
>>
>> So ... when _can_ I use class_variable_get ???


DM> You can use it whenever you want. When _should_ you use it?

DM> Like instance_variable_get, it's designed for metaprogramming -- that is, when
DM> you're trying to access a variable, but its name is dynamic.

DM> I'll give you an example of when instance_variable_get might be used. Remember
DM> attr_reader? (If not, look it up...) Now, for speed, attr_reader is defined
DM> in C, but it can be defined in Ruby. Here's the obvious 'eval' solution:

DM> class Module
DM> def attr_reader *names
DM> names.each do |name|
DM> eval "def #{name}; @#{name}; end"
DM> end
DM> end
DM> end

DM> But there are many reasons I dislike eval. Here's the solution I'd prefer:

DM> class Module
DM> def attr_reader *names
DM> names.each do |name|
DM> var_name = :"@#{name}"
DM> define_method name do
DM> instance_variable_get var_name
DM> end
DM> end
DM> end
DM> end

So, basically, the reason that instance_variable_get is private to
Module is that one does not wish make breaking encapsulation too easy?

I mean, it seems easy enough to break encapsulation by adding an
accessor, right?

DM> I don't expect you to follow every detail here. The use of define_method is an
DM> advanced topic already. Hopefully, though, the fact that you already know how
DM> to use attr_reader should give you an idea of how that works.

DM> Also, I don't really expect you to need any of this yet -- attr_reader,
DM> attr_writer, and attr_accessor should already do everything you need.

This is, actually, very lucid. I had few problems following any of it.

Also ... I _did_ try (successfully, I hope) to follow every detail.

Many many thanks.


 
Reply With Quote
 
Marnen Laibow-Koser
Guest
Posts: n/a
 
      11-28-2009
Ralph Shnelvar wrote
[...]
>
>>> MLK> (There is a way to call private methods from outside, but I will leave
>>> MLK> you to find it out on your own. It's not generally a good thing, and
>>> MLK> I'm not going to hand you a dangerous tool until you understand when
>>> not MLK> to use it.)
>>>
>>> So ... when _can_ I use class_variable_get ???

>
> DM> You can use it whenever you want. When _should_ you use it?
>
> DM> Like instance_variable_get, it's designed for metaprogramming --
> that is, when
> DM> you're trying to access a variable, but its name is dynamic.
>
> DM> I'll give you an example of when instance_variable_get might be
> used. Remember
> DM> attr_reader? (If not, look it up...) Now, for speed, attr_reader is
> defined
> DM> in C, but it can be defined in Ruby. Here's the obvious 'eval'
> solution:
>
> DM> class Module
> DM> def attr_reader *names
> DM> names.each do |name|
> DM> eval "def #{name}; @#{name}; end"
> DM> end
> DM> end
> DM> end
>
> DM> But there are many reasons I dislike eval. Here's the solution I'd
> prefer:
>
> DM> class Module
> DM> def attr_reader *names
> DM> names.each do |name|
> DM> var_name = :"@#{name}"
> DM> define_method name do
> DM> instance_variable_get var_name
> DM> end
> DM> end
> DM> end
> DM> end
>
> So, basically, the reason that instance_variable_get is private to
> Module is that one does not wish make breaking encapsulation too easy?
>
> I mean, it seems easy enough to break encapsulation by adding an
> accessor, right?


Wrong. attr_accessor really doesn't break encapsulation in the
conventional sense -- that is, it's not even remotely equivalent to
declaring a public data member in C++ or Java. Ruby has *no way* to
make instance variables public. This is a Good Thing.

attr_accessor just defines getter and setter methods -- and keeps the
variable encapsulated. When you do
@p = Person.new
@p.name = 'Ralph'
puts @p.name

the caller is making no assumptions at all about whether @p has an
instance variable called @name. It is impossible to tell from the code
supplied -- that detail is completely encapsulated. We assume that @p
has methods called :name and :name= , but that leaks nothing of @p's
internals.

Best,
--
Marnen Laibow-Koser
http://www.marnen.org
(E-Mail Removed)
>
> DM> I don't expect you to follow every detail here. The use of
> define_method is an
> DM> advanced topic already. Hopefully, though, the fact that you already
> know how
> DM> to use attr_reader should give you an idea of how that works.
>
> DM> Also, I don't really expect you to need any of this yet --
> attr_reader,
> DM> attr_writer, and attr_accessor should already do everything you
> need.
>
> This is, actually, very lucid. I had few problems following any of it.
>
> Also ... I _did_ try (successfully, I hope) to follow every detail.
>
> Many many thanks.


--
Posted via http://www.ruby-forum.com/.

 
Reply With Quote
 
Florian Gilcher
Guest
Posts: n/a
 
      11-29-2009
-----BEGIN PGP SIGNED MESSAGE-----
Hash: SHA1


On Nov 28, 2009, at 5:12 PM, Ralph Shnelvar wrote:
>
> So, basically, the reason that instance_variable_get is private to
> Module is that one does not wish make breaking encapsulation too easy?
>
> I mean, it seems easy enough to break encapsulation by adding an
> accessor, right?


The reason that instance_variable_get exists is solely to allow dynamic
lookup of instance variables to work in cases like define_method. It =20
is not
intended to be used from the outside, because it would unintentionally =20=

publish
all internal state of a class. This can be easily circumvented in such a
dynamic language like Ruby, but it has a big, fat warning sign =20
attached to it.


But even from the outside, it doesn't break one of the main properties =20=

of the
ruby language: the uniform access principle. There is only one way to
retrieve or change a value from/in an Object: by calling a method.
C++ and Java have two: directly accessing a member or calling a method.
In Ruby, this is especially true, because:

a.foo =3D "bar"

Is the same as sending the message :foo=3D to a.

a.send(:foo=3D, "bar")

where foo=3D is implemented as:

class A
def foo=3D(val)
#internal assignment
end
end

In every language it is easy to publish a value by adding a method. This
is not "breaking encapsulation", it is intentional publishing. If you =20=

don't
know what you are doing when implementing this method, no language can =20=

help
you. The way Ruby handles instance variables only makes it harder to =20
access
them in ways that the class implementer intended.

But even with instance_variable_get public, your only way of getting a =20=

value
would still be to call that method. Which would give the class =20
implementer
the possibility to delete, change or hook that method.

Regards,
Florian

[1]: http://en.wikipedia.org/wiki/Uniform_access_principle
- --
Florian Gilcher

smtp: (E-Mail Removed)
jabber: (E-Mail Removed)
gpg: 533148E2

-----BEGIN PGP SIGNATURE-----
Version: GnuPG/MacGPG2 v2.0.12 (Darwin)

iEYEARECAAYFAksR5PMACgkQyLKU2FMxSOLjWACdH+UwQoPd9N vQdXcxygsjDVBI
PLgAniLm2EMTmTnlZGne9Ep4I02D72Gb
=3DFlTZ
-----END PGP SIGNATURE-----

 
Reply With Quote
 
David Masover
Guest
Posts: n/a
 
      11-29-2009
On Saturday 28 November 2009 02:42:08 pm Ralph Shnelvar wrote:
> DM> It won't tell you how many Foo objects actually exist. It's more a
> count of DM> how many have ever been created.
>
> Cool.
>
> Is there a way to tell how many instances actually exist? Is there
> anything like a destructor for class instances? Just curious.


These are separate questions.

In MRI, you can tell how many instances exist by actually counting them. Look
at the documentation for ObjectSpace.

And yes, you can register a destructor -- that's also in ObjectSpace, and it's
called a "finalizer". But remember, Ruby is garbage-collected -- that means
you have absolutely no guarantee of _when_ that object will be removed. The
finalizer is guaranteed to be called before the program exits, but that's the
only guarantee you get.

Both of these are relatively advanced topics, and something that shouldn't be
needed in most programs. Keep in mind that in C++, then main purpose of a
destructor is to free resources used by the object in question -- and most of
these resources are simply other objects. So, the fact that Ruby is garbage-
collected removes most of the reason for destructors/finalizers.

An exception would be a resource that is more than just an object -- for
example, an open file, or a database handle. But these are generally much
scarcer resources than memory, so if at all possible, you want to manually
close these as soon as you can, rather than waiting for something to get
garbage collected. For example:

open 'some_file' do |file|
file.each_line do |line|
# do some stuff with each line in the file
end
end

What might not be obvious here is that the 'open' call will automatically
close the file when the block exits.

> So, basically, the reason that instance_variable_get is private to
> Module is that one does not wish make breaking encapsulation too easy?


Others have answered this already...

In a very basic sense, yes, that seems like a valid answer. There is really no
good reason why code outside a class should have to call
instance_variable_get, most of the time. It's private so that when you try,
you'll rethink your architecture so you don't need it.

On the other hand, Ruby has open classes. While there are ways to supposedly
lock it down and run untrusted code in a safe sandbox, in general, any code
running in the same interpreter can do all sorts of things to existing
classes. In other words, if you want to access the variable @bar in an object
of class Foo, you could always do something like this:

class Foo
attr_reader :bar
end

There are many other ways of getting the same result.

Now, Florian mentioned another aspect, which is that you still can only know
anything about an object by calling methods on it. So even if
instance_variable_get was public, there's nothing from stopping an especially
paranoid class from redefining it or removing it.

I think that's more than enough to answer your question, but if you're
curious, you could always have a sort of "arms race" of trying to enforce
encapsulation. For example, even if someone redefines instance_variable_get, I
can always do this:

Class.instance_method(:instance_method).bind(Foo). call(:instance_variable_get).bind(foo).call(:@bar)

That means there's nothing the Foo class itself can do to hide the @bar
variable from you, including redefining instance_method on itself.

But wait! How do you know Class itself hasn't been modified?

The lesson to learn here is that while Ruby is very good at encapsulation by
convention, it's not very good at all at enforced encapsulation, as C++ is. At
the end of the day, you have to remember that this is a language which lets
you define null to be not null. Here, try this in irb:

class NilClass
def nil?
false
end
end

Now type any other command, and watch irb crash.

> I mean, it seems easy enough to break encapsulation by adding an
> accessor, right?


Well, yes and no.

Yes, you can break encapsulation by just adding an accessor to any instance
variable that anyone was trying to hide from you. You can also break it by
using one of several tricks to call the private instance_variable_get, and
probably a few ways I haven't thought of. Ruby doesn't enforce encapsulation.

On the other hand, accessors are the ultimate in encapsulation -- partly
because they're the only sane way to get at instance variables, and partly
because they're so easy to define. I remember wishing for them in Java, where
good coding style led to lots of these:

private int foo;
public int getFoo() {
return foo;
}
public void setFoo(int value) {
foo = value;
}

I can see why Java people use tools like Eclipse -- there's no way you want to
type all that stuff yourself. But it's still a good idea, because it allows
you to change your internal structure to no longer require that variable,
without changing your external interface.

The point here is, if you actually expose an accessor, no one has to use
instance_variable_get or anything like it -- they won't be mucking about with
the internals of your class. (If they do, they're asking for trouble when you
change something.) That means you can, among other things, override the
behavior of the accessor on subclasses, replace it entirely with a method,
etc.

Just as an example: Suppose you have a class like this:

class Line
attr_reader :a, :b, :slope
def initialize(point_a, point_b)
@a = point_a
@b = point_b
@slope = (a.x - b.x) / (a.y - b.y)
end
end

Now, maybe later on, you notice this isn't working out too well -- maybe not
everyone cares about the slope, so you're wasting cycles calculating it every
time. Maybe the points are changing frequently, and you don't want to have to
re-calculate the slope on every change, only when someone requests it. Since
you defined slope as a reader method, you can just change your implementation:

class Line
attr_reader :a, :b
def slope
(a.x - b.x) / (a.y - b.y)
end
end

No one has to know that @slope no longer exists.

Granted, you might have some coders who deliberately break things by talking
to @slope directly, but if you've defined an accessor, they have to be a
masochist to want to do it that way. Similarly, because it's just one command
for you to define them, you really have no excuse not to.

I suppose that's the fundamental difference -- in Java and C++, encapsulation
can be enforced to some extent, while in Ruby, it can be easily circumvented.
But Ruby makes it easy to write well-encapsulated code, while Java and C++
make it annoying and tedious.

 
Reply With Quote
 
Ralph Shnelvar
Guest
Posts: n/a
 
      11-29-2009
DM> On Saturday 28 November 2009 02:42:08 pm Ralph Shnelvar wrote:
>> DM> It won't tell you how many Foo objects actually exist. It's more a
>> count of DM> how many have ever been created.
>>
>> Cool.
>>
>> Is there a way to tell how many instances actually exist? Is there
>> anything like a destructor for class instances? Just curious.


DM> These are separate questions.

[snip]

DM> I suppose that's the fundamental difference -- in Java and C++, encapsulation
DM> can be enforced to some extent, while in Ruby, it can be easily circumvented.
DM> But Ruby makes it easy to write well-encapsulated code, while Java and C++
DM> make it annoying and tedious.

Oh, wow, what a great explanation! Thanks for taking the time. Wow.


 
Reply With Quote
 
 
 
Reply

Thread Tools

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are Off


Similar Threads
Thread Thread Starter Forum Replies Last Post
Don't understand behavior; instance form a class in another class'instance Martin P. Hellwig Python 1 03-26-2010 12:06 AM
Can you set a class instance's attributes to zero by setting the instance to zero? Gerard Flanagan Python 3 11-19-2005 06:58 PM
Problem when subclass instance changes base class instance variable Gerry Sutton Python 1 04-16-2005 06:06 AM
converting base class instance to derived class instance Sridhar R Python 14 02-10-2004 02:47 PM
Cannot refer to an instance member of a class from within a shared method or shared member initializer without an explicit instance of the class. DJ Dev ASP .Net 3 02-08-2004 04:19 PM



Advertisments