James H.on wrote:
In either case, you’ve hit something that interests me. Conceptually,
I’d understood that the difference between an @-prepended variable and a
non-@-prepended variable is that the former is global to the object, so
it’s not impacted by the change in scope introduced by defining a method
inside the object. So I figured that describing the @ character as
changing the internal scope of a variable from local to global inside
the object wouldn’t be entirely missing the mark. But it’s possible I’m
missing something.
They are different in both scope and lifetime.
Instance variables (@foo) are a property of the object instance itself,
and once set, they remain for as long as the object exists, or until
reassigned. Calls to methods of the same object will see the same value
of @foo - even multiple concurrent calls in different threads.
Local variables are created in an activation record which is created
when the method is invoked, and so the values are not tied to the object
itself. If there are multiple calls to the method from multiple threads,
they will have their own activation records, and so independent local
variables. Normally the activation record is garbage-collected when the
method returns.
Now, I’m not sure I should be complicating things here, but activation
records may have extended lifetimes too, when closures are involved.
class Foo
def initialize(n)
@n = n
end
def make_adder(y)
lambda { |x| y + x }
end
end
f = Foo.new(1) # #<Foo @n=1>
a1 = f.make_adder(10)
a2 = f.make_adder(20)
a1.call(3) # 13
a1.call(4) # 14
a2.call(5) # 25
y is a local variable in make_adder, but it persists in the lambdas,
even after make_adder has returned. The two lambdas, a1 and a2, have
different values bound to y. But there is still only a single object of
class Foo.
My apologies if this has confused matters further But hopefully it
highlights how different these things are.
Regards,
Brian.