Dynamically defining a method on an instance that references vars in enclosing scope?

Hello. I want to do this.

instance = MyClass.new
x = 1
def instance.foo
puts x
end
undefined local variable or method `x’ for #MyClass:0x31ca8c4

How do get rid of that error?

Thanks for the help.

Hi –

On Sat, 22 Mar 2008, Christopher J. Bottaro wrote:

Hello. I want to do this.

instance = MyClass.new
x = 1
def instance.foo
puts x
end
undefined local variable or method `x’ for #MyClass:0x31ca8c4

How do get rid of that error?

You can use define_method, which takes a block and therefore can use
the local variables in scope at the time it’s called. You’d have to do
something equivalent to the familiar:

class Object
def singleton_class
class << self
self
end
end
end

(Aside to Matz: can we please have that in 1.9/2.0? :slight_smile:

and then:

instance.singleton_class.class_eval {
define_method(“foo”) { puts x }
}

David

The problem is of scope. foo is a method belonging to the ‘instance’
variable. ‘x’ is defined in global scope, but since its not $x its not
a global variable. When you start using x inside the method, the
interpreter doesn’t recognize a ‘x’ variable defined, hence the error.
Either, define x inside MyClass, or mark x as a global variable using
$x, which would make…


$x = 1
def instance.foo
puts $x
end

to: Christopher
I’d start off with a good introduction to scopes, that’ll clear this
scenario out. Plus buy the pickaxe book. Great read for beginners.

Hi –

On Sat, 22 Mar 2008, mutahhir hayat wrote:

def instance.foo
class Object

$x, which would make…


$x = 1
def instance.foo
puts $x
end

I know that the problem is scope. That’s why I suggested a way to
manipulate the scope :slight_smile:

I definitely would not (and deliberately did not) throw a global
variable at it. Also, defining x inside MyClass doesn’t help, because
that’s also a different local scope.

David

I know that the problem is scope. That’s why I suggested a way to
manipulate the scope :slight_smile:

I definitely would not (and deliberately did not) throw a global
variable at it. Also, defining x inside MyClass doesn’t help, because
that’s also a different local scope.

I wasn’t sure, but running an intermix of your code with the original
still would give the same error in irb. I wasn’t advocating the use of
globals, ( though, come to think about it, i do feel bad now even
mentioning it :P) but I didn’t consider that x wouldn’t be usable.

:slight_smile: I’m still getting used to this metaprogramming thing, but how did
you change scope? In my view, the scope remains exactly same, you just
allowed the method to be inserted into the object instance
dynamically.

Anyways, simplest i found was: (swearing never to mention global
again… :P)

class MyClass
attr_accessor :x
#… or if you want you could do

def initialize(x); @x = x; end

end

instance = MyClass.new

def instance.foo
puts x
end

instance.x = 1
instance.foo

would work.

MT.

On Sat, Mar 22, 2008 at 1:37 AM, David A. Black [email protected]
wrote:

that’s also a different local scope.

I wasn’t sure, but running an intermix of your code with the original
still would give the same error in irb. I wasn’t advocating the use of
globals, ( though, come to think about it, i do feel bad now even
mentioning it :P) but I didn’t consider that x wouldn’t be usable.

I don’t see the error:

Sorry, my bad, i rewrote it in my irb, and it validates your code. :slight_smile:
Must be getting to bed now, clock’s slowing.

irb(main):009:0* instance = Object.new

the locals that are already in scope.)

I get you, since the block passed to class_eval was defined in the
same scope as x, it would be knowledgeable about it. But tell me,
other than academic, won’t this be really bad to use? Like, maybe you
shadow some variable, and so on… I dunno, :stuck_out_tongue: as i said, nearing my
limit, so maybe i’m just jabbering here. But it was fun learning from
you, glad to be on this list. Thanks.

( Although, according to my judgment (sorry if i’m wrong) of the level
of the programmer by the nature of the question, i’m pretty sure we
made the questioner scream ) :slight_smile:

See ya,
MT

Hi –

On Sat, 22 Mar 2008, mutahhir hayat wrote:

mentioning it :P) but I didn’t consider that x wouldn’t be usable.
I don’t see the error:

irb(main):001:0> class Object
irb(main):002:1> def singleton_class
irb(main):003:2> class << self
irb(main):004:3> self
irb(main):005:3> end
irb(main):006:2> end
irb(main):007:1> end
=> nil
irb(main):008:0>
irb(main):009:0* instance = Object.new
=> #Object:0x64f50
irb(main):010:0> x = 1
=> 1
irb(main):011:0>
irb(main):012:0* instance.singleton_class.class_eval {
irb(main):013:1* define_method(“foo”) { puts x }
irb(main):014:1> }
=> #Proc:[email protected]:13(irb)
irb(main):015:0>
irb(main):016:0* instance.foo
1

:slight_smile: I’m still getting used to this metaprogramming thing, but how did
you change scope? In my view, the scope remains exactly same, you just
allowed the method to be inserted into the object instance
dynamically.

That’s the thing: I didn’t change scope. The block that uses x (line
013 above) is in the same scope as the line that defines x (010) – at
least, in the same scope block-style. (Meaning: the block can see all
the locals that are already in scope.)

def instance.foo
puts x
end

instance.x = 1
instance.foo

would work.

Yes, but you’ve shifted to instance variables. That’s a more common
use case than the class_eval/define_method one, but they’re both worth
knowing about.

David

Hi –

On Sat, 22 Mar 2008, mutahhir hayat wrote:

I get you, since the block passed to class_eval was defined in the
same scope as x, it would be knowledgeable about it. But tell me,
other than academic, won’t this be really bad to use? Like, maybe you
shadow some variable, and so on… I dunno, :stuck_out_tongue: as i said, nearing my
limit, so maybe i’m just jabbering here. But it was fun learning from
you, glad to be on this list. Thanks.

One of the most important roles of code blocks is to serve as closures
– that is, functions that remember the context of their own creation.
In Ruby 1.9, the rules of parameter assignment are changing somewhat,
so that it’s easier to avoid trampling outside variables; but you can
still use those variables if that’s your purpose.

David

On Mar 21, 1:26 pm, “David A. Black” [email protected] wrote:

One of the most important roles of code blocks is to serve as closures
That is what I was going for. Thank you for your solution!

You’d have to do something equivalent to the familiar:
class Object
def singleton_class
class << self
self
end
end
end

Though I more or less understand what that is doing, it’s not
“familiar” to me. Can you tell me name of that idiom or point me in
the direction of where it is discussed?

I do understand that if I simply do something like

my_instance.class.define_method :name do

blah blah

end

Then ‘name’ will be defined for all instances of the class and not
just for the few instances that I want.

Thanks again.

<off_topic_rant>
I wish Google G. would send email notification to threads I
participate in by default. So many times I forget that I even posted
until months later.
</off_topic_rant>

This forum is not affiliated to the Ruby language, Ruby on Rails framework, nor any Ruby applications discussed here.

| Privacy Policy | Terms of Service | Remote Ruby Jobs