Scope in Method Definitions

C

Curt Sampson

Presumably there's some theory behind this, but this is a seeming
inconsistency in the language that I don't understand.

foo = "foo"
C = Class.new() {
def method1; puts foo; end
define_method:)method2) { puts foo }
}

C.new.method2 # prints "foo"
C.new.method1 # NameError: undefined local variable or method `foo'

Can someone explain why this is sensible behaviour?

cjs
 
G

Gennady Bystritsky

Presumably there's some theory behind this, but this is a seeming
inconsistency in the language that I don't understand.

foo = "foo"
C = Class.new() {
def method1; puts foo; end

Here method1's local variable (as there's no foo() method so far) is
being referenced and it is not defined.
define_method:)method2) { puts foo }

Here a block is used that defines the closure referencing the local
variable foo from the current scope.
Looks pretty consistent ;-)

Oh, yes, a block is used to define a class body, I see. However, "def"
syntax prevents "foo" from being treated as a closure participant. At
least, it is how it looks to me ;-).
C.new.method2 # prints "foo"
C.new.method1 # NameError: undefined local variable or method `foo'

Can someone explain why this is sensible behaviour?

cjs

Gennady.
 
C

Curt Sampson

Oh, yes, a block is used to define a class body, I see. However, "def"
syntax prevents "foo" from being treated as a closure participant. At
least, it is how it looks to me ;-).

Bingo! After a bit more playing, it looks like the "class" statement
does this too.

This is not so hard to live with, once you know. The problem is, the
language makes finding out this stuff so darn tough.

If you want to see what this was all about, I've appended a nifty little
bit of code. (I'm using it with a factory that stores Classes, and
later instantiates them; this saves me having to store parameters for
new as well.) It took me quite some time to work out that I had to use
define_method instead of def.

cjs
--
Curt Sampson <[email protected]> +81 90 7737 2974 http://www.NetBSD.org
Make up enjoying your city life...produced by BIC CAMERA


# $Id: curry.rb,v 1.1 2005/04/13 05:41:38 cjs Exp $

require 'test/unit/testcase'

def curryclass(klass, *curried_args)
curried_class = Class.new(klass) {
def initialize(*args)
super_args = curried_args + args
super(*super_args)
end
}
curried_class
end

class TC_curryclass < Test::Unit::TestCase

class AddPair
def initialize(a, b)
@value = a + b
end
attr_reader :value
end

AddTwoAndFour = curryclass(AddPair, 2, 4)

AddTwo = curryclass(AddPair, 2)

def FAILING test_curryclass
assert_equal(5, self.class::AddPair.new(2, 3).value)
assert_equal(6, self.class::AddTwoAndFour.new.value)
assert_equal(7, self.class::AddTwo.new(5).value)
end

def test_nothing
end

end
 
P

Pit Capitain

Curt said:
Presumably there's some theory behind this, but this is a seeming
inconsistency in the language that I don't understand.

foo = "foo"
C = Class.new() {
def method1; puts foo; end
define_method:)method2) { puts foo }
}

C.new.method2 # prints "foo"
C.new.method1 # NameError: undefined local variable or method `foo'

Can someone explain why this is sensible behaviour?

Your code can be reduced to

foo = "foo"
def m1; p foo; end
m2 = lambda { p foo }

m2.call # => "foo"
m1.call # => NameError

Does this help?

Regards,
Pit
 
R

Robert Klemme

Curt Sampson said:
Bingo! After a bit more playing, it looks like the "class" statement
does this too.

This is not so hard to live with, once you know. The problem is, the
language makes finding out this stuff so darn tough.

If you want to see what this was all about, I've appended a nifty little
bit of code. (I'm using it with a factory that stores Classes, and
later instantiates them; this saves me having to store parameters for
new as well.) It took me quite some time to work out that I had to use
define_method instead of def.

cjs
--
Curt Sampson <[email protected]> +81 90 7737 2974 http://www.NetBSD.org
Make up enjoying your city life...produced by BIC CAMERA


# $Id: curry.rb,v 1.1 2005/04/13 05:41:38 cjs Exp $

require 'test/unit/testcase'

def curryclass(klass, *curried_args)
curried_class = Class.new(klass) {
def initialize(*args)
super_args = curried_args + args
super(*super_args)
end
}
curried_class
end

I'd probably do it either of these ways:

# straightforward, but need to invoke #call
def curryclass(cl,*args)
lambda { cl.new(*args) }
end

# if you need "new"
def curryclass(cl,*args)
l = lambda { cl.new(*args) }
class <<l; alias :new :call; end
l
end

# another way
def curryclass(cl,*args)
o = Object.new
class <<o;self;end.define_method:)new){cl.new(*args)}
o
end

Kind regards

robert
 

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

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top