When the following code is evaluated
def foo ; "foo" ; end
where does the method go? Here is what I would guess.
If the evaluation context of the def is a class, then the method is an
instance method of the class. If the evaluation context of the def is
not a class, then the method is a singleton method of the context
object.
This rule is ugly, but it almost always works. What I don't understand
is the one exception below. Here are the non-exceptions:
class X
def foo ; "foo" ; end # #method of X
end
X.new.foo # works
obj = []
class <<obj
def foo ; "foo" ; end # singleton method of obj
end
obj.foo # works
class Y
def def_foo
def foo ; "foo" ; end # singleton method of Y instances
end
end
y = Y.new
y.def_foo
y.foo # works
class Z
def Z.def_foo
def foo ; "foo" ; end # #method of Z
end
def_foo
end
Z.new.foo # works
And here is the exception:
module Definer
def def_foo
def foo ; "foo" ; end # class method of User !
end
end
class User
extend Definer
def_foo
end
User.foo # works!
User.new.foo # error!
Bug or feature? In particular, why should Z and User give different
results?
PS: All my talk of "execution context" I picked up off the street. I
don't find it discussed in "Programming Ruby" or "The Ruby Way".
···
--
Posted via http://www.ruby-forum.com/.
not quite. see "Defining a Method" of the pickaxe ed 2 on page 330.
···
On Nov 10, 2007, at 23:40 , Greg Weeks wrote:
When the following code is evaluated
def foo ; "foo" ; end
where does the method go? Here is what I would guess.
If the evaluation context of the def is a class, then the method is an
instance method of the class. If the evaluation context of the def is
not a class, then the method is a singleton method of the context
object.
Not a singleton method. It's just a delayed definition of a standard
instance method:
class Bar
def def_foo
def foo
"foo"
end
end
end
b1 = Bar.new
b2 = Bar.new
p b1.foo rescue p "error"
#=> "error"
b1.def_foo
p b1.foo
#=> "foo"
p b2.foo
#=> "foo"
···
On Nov 10, 11:40 pm, Greg Weeks <gregwe...@shaw.ca> wrote:
class Y
def def_foo
def foo ; "foo" ; end # singleton method of Y instances
end
end
y = Y.new
y.def_foo
y.foo # works
Ryan Davis wrote:
not a class, then the method is a singleton method of the context
object.
not quite. see "Defining a Method" of the pickaxe ed 2 on page 330.
In my copy, the heading is "Method Definition", and it begins on pg 345.
Are you referring to the paragraph that begins with "Outside a class or
module definition"? That refers to the top-level (I believe). I
omitted that example deliberately since a person who typed it in would
mess up the subsequent examples. Here it is:
def foo ; "foo" ;end
.foo # works
By the way, I regret my statement that the rule that I stated was ugly.
I thought that I was being self-deprecating about my phrasing of the
rule. But on second thought, neither the phrasing nor the rule is ugly.
However, it doesn't seem to work in the Definer/User example.
···
On Nov 10, 2007, at 23:40 , Greg Weeks wrote:
--
Posted via http://www.ruby-forum.com/\.
Ryan Davis wrote:
not a class, then the method is a singleton method of the context
object.
not quite. see "Defining a Method" of the pickaxe ed 2 on page 330.
I now see that you're right. The Pick-axe book explains everything:
"A method definition using an unadorned method name within a class
or module definition creates an instance method".
Here, "within" means lexically within, not dynamically within. This
explains my problem case:
module Definer
def def_foo
def foo ; "foo" ; end # class method of User !
end
end
class User
extend Definer
def_foo
end
User.foo # works!
User.new.foo # error!
The def of foo is dynamically within User, but it is lexically within
Definer. (The fact that it is nested doesn't matter.) Consequently,
foo becomes an instance method of Definer.
This also implies (correctly) that the foo method of y is a common
method, not a singleton method. So I was wrong about that too. But I
think I've got it now. Yippee!
···
On Nov 10, 2007, at 23:40 , Greg Weeks wrote:
--
Posted via http://www.ruby-forum.com/\.
It actually looks pretty cool:
% parse_tree_show -u
# ...
^D
s(:class,
:Bar,
nil,
s(:scope,
s(:defn,
:def_foo,
s(:args),
s(:scope,
s(:block,
s(:defn, :foo, s(:args), s(:scope, s(:block, s(:str, "foo")))))))))
So the defn foo is just sitting inside. Whenever def_foo gets executed, the defn inside gets interpreted, defining the new foo in whatever context it is executing in.
···
On Nov 11, 2007, at 08:50 , Phrogz wrote:
Not a singleton method. It's just a delayed definition of a standard
instance method:
class Bar
def def_foo
def foo
"foo"
end
end
end
After some more thought, the rule that instance methods go into the
lexically enclosing class has surprised me again. Let x = []. I had
thought that the following two methods behaved identically (except for
"foo vs bar", of course):
def x.define_foo
def foo ; "foo" ; end
end
class << x
def define_bar
def bar ; "bar" ;end
end
end
However, in the first case the lexically enclosing class is Object
(well, you know what I mean), and in the second case the lexically
enclosing class is the singleton class of x. So the rule says
(correctly) that the two are different:
x.define_foo
Object.instance_methods.include? "foo" # true
x.singleton_methods.include? "foo" # false
x.define_bar
Object.instance_methods.include? "bar" # false
x.singleton_methods.include? "bar" # true
Good!, I think. But there is still one case where I don't know where
the "def" should go:
x.instance_eval { def baz ; "baz" ; end }
What class acts as the effective enclosing class of the def? Is it
Object, the actual enclosing class? Or Array, the class of x? Or
is it the singleton class of x? The answer is the latter:
x.singleton_methods.include? "baz" # true
Whew!
···
--
Posted via http://www.ruby-forum.com/.
BTW, as I now understand it, I grabbed the wrong end of the stick when I
concerned myself with nested defs. I'm pretty sure that no good program
does this, not for an inner instance method anyway. "define_method" is
always preferable. (Counterexample, anyone?) In that case, a practical
response to the question of how nested defs behave is to not care. I
*think* that that is the right response. As a newcomer, though, I can't
say for sure.
···
--
Posted via http://www.ruby-forum.com/.