Callback for instance var creation?

T

T. Onoma

Is there a callback for when an instance variable is first used? I know they
are "instantiated" upon use and set to nil. I would like to set this to
something else dependent on the name of the variable.

Thanks,
T.
 
R

Robert Klemme

T. Onoma said:
Is there a callback for when an instance variable is first used? I know they
are "instantiated" upon use and set to nil.

No, they are instantiated on first assignment:
nil
=> nil
=> # said:
f.instance_variables => []
f.instance_eval { @bar = "yes" } => "yes"
f
=> # said:
f.instance_variables
=> ["@bar"]
I would like to set this to
something else dependent on the name of the variable.

Which problem are you trying to solve? Usually attribute accessors can do
what you want.

class Foo
attr_accessor :bar
def bar=(b)
@bar = "foo #{b}"
end
end

Other than that if you need to intercept all variable settings a modified
Hash might be better for managing your instance vars:

class Foo
class FooHash < Hash
def []=(k,v)
case k
when :foo
super(k, "bar #{v}")
else
super
end
end
end

def initialize
@vars = FooHash.new
end

def method_missing(sym, *args, &b)
case sym.to_s
when /^(\w+)=$/
@vars[$1.intern] = args[0]
when /^(\w+)$/
@vars[sym]
else
super
end
end
end

This of course is just an example. It depends on the real problem at hand
that you are trying to solve.

Regards

robert
 
T

T. Onoma

No, they are instantiated on first assignment:

Oh! I didn't realize b/c if you assign from one that doesn't exist, it returns
nil.

irb(main):001:0> x=@x
=> nil
irb(main):002:0> p x
nil
=> nil
Which problem are you trying to solve? Usually attribute accessors can do
what you want.

Actually, its esoteric. I've been thinking about methods as 1st class objects.
At one point I have suggested that constants be used. See:

http://www.rubygarden.org/ruby?FirstClassMethods

But constants are class-level while methods are actually instance level
(strangely enough). So I thought if they were instance level perhaps an
instance variable would be better. Using the capitalization idea from before,
something like:

def ameth(x)
puts x
end

p @Ameth # => #<Method: Object#ameth>

So I was trying to auto-assign @Ameth.
Other than that if you need to intercept all variable settings a modified
Hash might be better for managing your instance vars:

Perhaps something like that would be better. I'll give it some thought.

Thanks!
T.
 
F

Florian Gross

T. Onoma said:
Actually, its esoteric. I've been thinking about methods as 1st class objects.
At one point I have suggested that constants be used. See:

Actually I think the best way to do this would be like this:

obj = Object.new
obj.method:)foo) = self.method:)puts)
obj.foo(5)

Regards,
Florian Gross
 
T

T. Onoma

Actually I think the best way to do this would be like this:

obj = Object.new
obj.method:)foo) = self.method:)puts)
obj.foo(5)

Not sure how that provides 1st class methods. The idea is to be able to store
state in methods and give them singletons, etc. For instance:

def ameth
puts Time.now
end

# if ameth were a first class object
def ameth.tag
:log
end

Calling method:)ameth) doesn't work because it creates a new method object
everytime and therefore looses state. Plus it is overly verbose.

There have been other suggested notations like:

::meth
\meth
 
F

Florian Gross

T. Onoma said:
Calling method:)ameth) doesn't work because it creates a new method object
everytime and therefore looses state. Plus it is overly verbose.

Oh, a cache could be added easily. Can't do anything about the verbosity
however.

Regards,
Florian Gross
 
T

T. Onoma

Oh, a cache could be added easily. Can't do anything about the verbosity
however.

Yes, perhaps I will add a cache to method. Then I'll have three working
implementations of this:

1. method:)ameth) # per above
2. :ameth[self] # modifies symbol class
3. Ameth() # using missing_method and capitalization

The later is of course a take-off of the constant version (non-implementable)
but in this case you have to use the parentheses. All of these, obviously,
have their disadvantages.

I think probably the best way to actually do this is to change how :: works.

Currently it works like this:

Foo.Bar() # method call
Foo.Bar # method call
Foo.bar() # method call
Foo.bar # method call
Foo::Bar() # method call
Foo::Bar # constant lookup
Foo::bar() # method call
Foo::bar # method call

I suggest this instead:

Foo.Bar() # method call
Foo.Bar # method call
Foo.bar() # method call
Foo.bar # method call
Foo::Bar() # method call
Foo::Bar # constant lookup
Foo::bar() # method call
Foo::bar # 1st class method

The only shortcoming here is that capitalized methods can't be accessed this
way b/c they interfere with constants. But that's very very minor point. With
this in place you could easily access 1st class methods like this:

::ameth
 
R

Robert Klemme

T. Onoma said:
Oh! I didn't realize b/c if you assign from one that doesn't exist, it returns
nil.

irb(main):001:0> x=@x
=> nil
irb(main):002:0> p x
nil
=> nil



Actually, its esoteric. I've been thinking about methods as 1st class
objects.

Methods *are* first class objects:
=> #<Method: Foo#bar>

And similar to functional languages, functions are also first class objects
and you can work functional style in Ruby, too:
plus = lambda {|a, b| a + b}
=> # said:
plus[ 1, 2 ] => 3
curry = lambda {|f, *args| lambda {|*x| f.call(*(args + x))} }
=> # said:
plus5 = curry[ plus, 5 ]
=> # said:
plus5[ 10 ]
=> 15
At one point I have suggested that constants be used. See:

http://www.rubygarden.org/ruby?FirstClassMethods

But constants are class-level while methods are actually instance level
(strangely enough).

Not necessarily, see the first code example above (UnboundMethod). Note
also that you can convert between the two types:
=> # said:
So I thought if they were instance level perhaps an
instance variable would be better. Using the capitalization idea from before,
something like:

def ameth(x)
puts x
end

p @Ameth # => #<Method: Object#ameth>

So I was trying to auto-assign @Ameth.


Perhaps something like that would be better. I'll give it some thought.

It seems the easiest to do would be to include a Hash for method instances
if you want to maintain state:

class Object
alias :eek:ld_method :method
def method(s)
( @methods ||= {} ) ||= old_method(s)
end
end
class Foo
def bar;end
end => nil
f= Foo.new
=> # said:
f.method( :bar ).id => 135011952
f.method( :bar ).id => 135004308
class Object
alias :eek:ld_method :method
def method(s)
( @methods ||= {} ) ||= old_method(s)
end
end => nil
f.method( :bar ).id => 134638968
f.method( :bar ).id

=> 134638968

Kind regards

robert
 
T

T. Onoma

Methods *are* first class objects:

Yes, in one sense they are. That's true. But not in the sense that they
readily accessable and *carry state* (as in Python, FWIBT). That's the
important missing element.
Not necessarily, see the first code example above (UnboundMethod). Note

also that you can convert between the two types:



=> #<Method: Foo#bar>

Hmm... I see more clearly now how rebinding unbound methods "reinstates" the
method. But still, unbound methods seem useless. They can only be rebound to
the same kind of class. Until that changes what real use are they? But
perhaps in the future...(matz?) Then again I think someone did once show me
an example of how unbound methods could be useful, but it was rather tricky
and hence not very useful ;)

Hmmm... but I do see that I might be able to finish my original proposal using
them. That might work. So the constant method would be the class-level
version. Oh, that might blend nicely with the capitalized methods for the
instance level version --they will look identical except for the parens.

Ameth - unbound
Ameth() - bound

Not bad. Perhaps with a little extra umph I can use that absent argument too.
Maybe for bounding to a different object? [just thinking out loud here]
class Object
alias :eek:ld_method :method
def method(s)
( @methods ||= {} ) ||= old_method(s)
end
end


nice. a bit more concise then my version. that will work, despite the extra
verbosity, method:)ameth) -or- @methods[:ameth].

thanks,
T.
 
R

Robert Klemme

T. Onoma said:
Yes, in one sense they are. That's true. But not in the sense that they
readily accessable and *carry state* (as in Python, FWIBT). That's the
important missing element.


Hmm... I see more clearly now how rebinding unbound methods "reinstates" the
method. But still, unbound methods seem useless. They can only be rebound to
the same kind of class.

And you can query arity. Plus you can store anything that you like to in
them (i.e. add state of your own). Just apply the pattern I presented for
#method to Class#instance_method and you'll get the same instance each time
you access a method. Note though that this approach doesn't take into
consideration changes of the method definition *after* it was put into the
hash. That might be a serious drawback depending on whether or not you need
to cope with this.
Hmmm... but I do see that I might be able to finish my original proposal using
them. That might work. So the constant method would be the class-level
version. Oh, that might blend nicely with the capitalized methods for the
instance level version --they will look identical except for the parens.

Personally I don't like at all introducing a constant for each method in a
class. Plus, methods are not constant i.e. you can redefine them.

What kind of state do you want to attach to methods? I mean, what problem
are you trying to solve?

robert
 
T

T. Onoma

Personally I don't like at all introducing a constant for each method in a
class. Plus, methods are not constant i.e. you can redefine them.

That what everybody says! (Because of the namespace pollution, I guess.)

On the later point, constants in Ruby aren't necessarily so constant.
Constants can be hashes or arrays and their internal contents can readily
change too --and that's useful.
What kind of state do you want to attach to methods? I mean, what problem
are you trying to solve?

AOP. In AOP advice wrap methods, so if methods have state, then wrapping can
be dependent on that state (like arity). On the other hand, just having a
clean syntax for accessing them is nice too.

I still like ::ameth, best.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
474,156
Messages
2,570,878
Members
47,408
Latest member
AlenaRay88

Latest Threads

Top