Why do inner methods count in outer scope?


(Charles Comstock) #1

def foo(x)
def bar(n)
n + 1
end
bar(x)
end

foo(5) # -> 6
bar(5) # -> 6

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?

Charlie


(Nobuyoshi Nakada) #2

Hi,

At Wed, 3 Mar 2004 15:44:46 +0900,
Charles Comstock wrote in [ruby-talk:94119]:

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?

Current inner method just keeps undefined until the outer
method executes, but has no lexical scope at all.

suspect this is still transient behavior and will be changed

in the future, just my 2yen.

···


Nobu Nakada


(Gavin Sinclair) #3

def foo(x)
def bar(n)
n + 1
end
bar(x)
end

foo(5) # ->> 6
bar(5) # ->> 6

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?

Heh, I thought “def inside def” wasn’t even allowed!

Gavin

···

On Wednesday, March 3, 2004, 5:44:46 PM, Charles wrote:


(Mark Hubbart) #4

Intended feature :slight_smile:

Method definitions are scoped the same way as @variables; the new
method is added to the current instance. It doesn’t matter if you do it
at the “base level” of the class, or if you stick it ten layers down
inside blocks of code, it still gets added to the instance.

 class Foo
   def bar
     def quux
       "quux!"
     end
     "defined quux..."
   end
 end
     ==>nil
 f=Foo.new
     ==>#<Foo:0x63300>
 f.methods - Object.new.methods
     ==>["bar"]
 f.quux
 NoMethodError: undefined method `quux' for #<Foo:0x63300>
         from (irb):11
 f.bar
     ==>"defined quux..."
 f.quux
     ==>"quux!"
 f.methods - Object.new.methods
     ==>["bar", "quux"]

–Mark

···

On Mar 2, 2004, at 10:44 PM, Charles Comstock wrote:

def foo(x)
def bar(n)
n + 1
end
bar(x)
end

foo(5) # -> 6
bar(5) # -> 6

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?


(Tim Bates) #5

Probably quite intentional; I quite often use it for dynamic
(re)definition of methods and would be annoyed if it went away…

I suggest if you need this behaviour, use a proc literal assigned to a
local variable, thus:

def foo(x)
bar = proc do |n|
n + 1
end
bar.call(x) # or bar[x]
end

foo(5) # -> 6
bar(5) # -> wtf? I don’t know what bar is.

Tim.

···

nobu.nokada@softhome.net wrote:

At Wed, 3 Mar 2004 15:44:46 +0900,
Charles Comstock wrote in [ruby-talk:94119]:

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?


Tim Bates
tim@bates.id.au


(Joel VanderWerf) #6

Mark Hubbart wrote:

def foo(x)
def bar(n)
n + 1
end
bar(x)
end

foo(5) # -> 6
bar(5) # -> 6

Why is bar escaping the scope of foo? Is this a bug, or an unintended
feature?

Intended feature :slight_smile:

Method definitions are scoped the same way as @variables; the new method
is added to the current instance. It doesn’t matter if you do it at the
^^^^^^^^

Not exactly. It can be added to the current class, if that is the scope:

class A
def foo
def bar; p “BAR”; end
end
end

a = A.new
b = A.new

a.foo
b.bar # ==> “BAR”

···

On Mar 2, 2004, at 10:44 PM, Charles Comstock wrote:


(Charles Comstock) #7

Tim Bates wrote:

···

nobu.nokada@softhome.net wrote:

At Wed, 3 Mar 2004 15:44:46 +0900,
Charles Comstock wrote in [ruby-talk:94119]:

Why is bar escaping the scope of foo? Is this a bug, or an
unintended feature?

Probably quite intentional; I quite often use it for dynamic
(re)definition of methods and would be annoyed if it went away…

I suggest if you need this behaviour, use a proc literal assigned to a
local variable, thus:

def foo(x)
bar = proc do |n|
n + 1
end
bar.call(x) # or bar[x]
end

foo(5) # -> 6
bar(5) # -> wtf? I don’t know what bar is.

Tim.

Nah, I don’t really need it, I was just trying to scope out what the
language was capable of scoping wise. Out of curiosity, why don’t you
just use an eval to change function definitions? It would be much nicer
I think if it worked as another way to generate a closure, but bound in
the outer scope. But maybe I’m just not following what your using it for.

Charles Comstock


(HAL 9000) #8

Joel VanderWerf wrote:

Method definitions are scoped the same way as @variables; the new
method is added to the current instance. It doesn’t matter if you do
it at the

                      ^^^^^^^^

Not exactly. It can be added to the current class, if that is the scope:

class A
def foo
def bar; p “BAR”; end
end
end

It’s still the current instance. The current instance here happens
to be a class.

Hal


(Joel VanderWerf) #9

Hal Fulton wrote:

Joel VanderWerf wrote:

Method definitions are scoped the same way as @variables; the new
method is added to the current instance. It doesn’t matter if you do
it at the

                      ^^^^^^^^

Not exactly. It can be added to the current class, if that is the scope:

class A
def foo
def bar; p “BAR”; end
end
end

It’s still the current instance. The current instance here happens
to be a class.

That use of “current instance” is confusing to me. Maybe “current
definition scope” would be better. Words are more confusing than code…

class A
def foo
p self
def bar; p “BAR”; end
end
end

a = A.new
a.foo # ==> #<A:0x401c6da4>

Inside #foo, self refers to the instance of A. Yet, as my previous
example showed, the method was added as an instance method of class A,
not as a method of object A or as a singleton method of the instance of A.


(Tim Bates) #10

Charles Comstock wrote:

Out of curiosity, why don’t you just use an eval to change function
definitions?

I do. Watch:

def mk_func(:name)
eval <<-EOF
def #{name}(foo)
puts foo
end
EOF
end

Even when using eval, you’ve got to use a def keyword somewhere to
define a method. As far as I’m concerned, the example above should be
equivalent to

def mk_func2
def bar(foo)
puts foo
end
end

With the exception of course that the name of the function is not
dynamic, which is why we use eval in the first place. The point I’m
making, however, is that the scoping rules for the inner function in
both examples should be equivalent, and that without the scoping being
as it is I would be unable to dynamically define methods in this manner.

Tim.

···


Tim Bates
tim@bates.id.au


(HAL 9000) #11

Joel VanderWerf wrote:

Hal Fulton wrote:

It’s still the current instance. The current instance here happens
to be a class.

That use of “current instance” is confusing to me. Maybe “current
definition scope” would be better. Words are more confusing than code…

[snip]

I think I have misspoken. Let me examine this. Sorry…

Hal


(David A. Black) #12

Hi –

Charles Comstock wrote:

Out of curiosity, why don’t you just use an eval to change function
definitions?

I do. Watch:

def mk_func(:name)
eval <<-EOF
def #{name}(foo)
puts foo
end
EOF
end

Even when using eval, you’ve got to use a def keyword somewhere to
define a method.

You can use define_method, if you want to avoid both eval and def.
Also, this gives you some control over scope, because you can put the
new method in either the class of the object (so that other instances
will be able to call it) or in the object’s singleton class.

class A
  def mk_func(n)
self.class.class_eval {

or: (class << self; self; end).class_eval {

  define_method(n, proc {|foo| puts foo })
}
  end
end

(Yes, I know that class_eval is in the eval family :slight_smile: But you can
avoid eval’ing strings this way.)

David

···

On Thu, 4 Mar 2004, Tim Bates wrote:


David A. Black
dblack@wobblini.net