>> 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!
Didn't the interpreter parse it?
If I do
class X
def y
xyzzy = 3++
end
endthen 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[:x] = :y
end
Would you expect SomeHash[:x] 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[:x] 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.
Cool.
Is there a way to tell how many instances actually exist? Is there
anything like a destructor for class instances? Just curious.
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?
> (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 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
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?
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.
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.
···
On Saturday 28 November 2009 08:43:30 am Ralph Shnelvar wrote: