Scope in Method Definitions

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

···

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

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 :wink:

    }

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
--
Curt Sampson <cjs@cynic.net> +81 90 7737 2974 http://www.NetBSD.org
     Make up enjoying your city life...produced by BIC CAMERA

Gennady.

···

On Apr 12, 2005, at 11:21 PM, Curt Sampson wrote:

Curt Sampson schrieb:

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

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

···

On Wed, 13 Apr 2005, Gennady Bystritsky wrote:

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 ;-).

--
Curt Sampson <cjs@cynic.net> +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

"Curt Sampson" <cjs@cynic.net> schrieb im Newsbeitrag
news:Pine.NEB.4.62.0504131544280.19224@angelic.cynic.net...

> 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 <cjs@cynic.net> +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

···

On Wed, 13 Apr 2005, Gennady Bystritsky wrote:

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