Self in blocks

Hi

This seems to me somehow inconsistent:

class A; end

# 1)
# output A
A.class_eval { puts self }

# 2)
# output main (in irb)
[1].each { puts self }

The "problem" to me is that in 1) 'self' seems to refer to the context
where yield is called, where in 2) seems to refer to the context in
execution.
What should i expect from 'self'`s behaviour?

Tks
Vasco A. Silva

···

--
Posted via http://www.ruby-forum.com/.

self will normally refer to self in the lexical scope of the block (#2). class_eval, module_eval, instance_eval, and instance_exec are special exceptions to this rule.

-mental

···

On Fri, 11 May 2007 06:37:07 +0900, Vasco Andrade e silva <vascoas@gmail.com> wrote:

The "problem" to me is that in 1) 'self' seems to refer to the context
where yield is called, where in 2) seems to refer to the context in
execution.
What should i expect from 'self'`s behaviour?

Hi --

Hi

This seems to me somehow inconsistent:

class A; end

# 1)
# output A
A.class_eval { puts self }

# 2)
# output main (in irb)
[1].each { puts self }

The "problem" to me is that in 1) 'self' seems to refer to the context
where yield is called, where in 2) seems to refer to the context in
execution.
What should i expect from 'self'`s behaviour?

self doesn't really behave; it just plays the role it's assigned to
play in different circumstances. class_eval sets self to the
receiver (it's specially designed for that purpose -- basically a
programmatic rather than declarative way to enter a class definition
block). In general, though, self doesn't change when you enter a
code block. That's why self is still main inside your second block.

David

···

On Fri, 11 May 2007, Vasco Andrade e silva wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

One of the purposes of of #class_eval is to explicitly change
the binding of self within the block. By calling #class_eval
you are asking that self be bound to A (for your example) while
the block is executing. This is a behavior of class_eval and
not of blocks in general, which is why in:

[1].each { puts self }

self isn't bound to the array.

Gary Wright

···

On May 10, 2007, at 5:37 PM, Vasco Andrade e silva wrote:

# 1)
# output A
A.class_eval { puts self }

MenTaLguY wrote:

self will normally refer to self in the lexical scope of the block (#2).
class_eval, module_eval, instance_eval, and instance_exec are special
exceptions to this rule.

-mental

I confess I don't like this approach :S (rules with exceptions, doesn't
fit right..) however thanks for the explanations.
By the way are class_eval, module_eval, instance_eval and instance_exec
the only exceptions?

Vasco A. Silva

···

--
Posted via http://www.ruby-forum.com/\.

Hi --

MenTaLguY wrote:

self will normally refer to self in the lexical scope of the block (#2).
class_eval, module_eval, instance_eval, and instance_exec are special
exceptions to this rule.

-mental

I confess I don't like this approach :S (rules with exceptions, doesn't
fit right..) however thanks for the explanations.
By the way are class_eval, module_eval, instance_eval and instance_exec
the only exceptions?

I think so. (I can't remember what instance_exec does/will do, but
that's neither here nor there.) It's not really rule plus exception;
it's more a kind of hand-crafted quality to the language that provides
a nice assortment of the facilities that people actually need, with
attention paid to the naming. It's another example of why I have
always said that Ruby represents "the triumph of balance over
symmetry" :slight_smile:

David

···

On Fri, 11 May 2007, Vasco Andrade e silva wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

In Ruby's core library, yes. It's possible to implement new methods with similar behavior (which is occasionally useful), but that isn't the norm.

-mental

···

On Fri, 11 May 2007 07:06:29 +0900, Vasco Andrade e silva <vascoas@gmail.com> wrote:

By the way are class_eval, module_eval, instance_eval and instance_exec
the only exceptions?

For example:

class Person
  attr_accessor :name, :age
  def initialize( name )
    @name = name
    @age = 0
  end
  def grow_older
    @age += 1
  end
end

def create( name, &block )
  person = Person.new( name )
  person.instance_eval( &block )
  p person
end

create( :gavin ){
  @age = 32
  grow_older
}
#=> #<Person:0x28347c4 @age=33, @name=:gavin>

Using instance eval makes some DSLs (domain specific languages) easier
to create, rather than having to use the object yielded to the block
in every call. Compare the usage of 'create' above to this usage:

def create( name )
  person = Person.new( name )
  yield person
  p person
end

create( :gavin ){ |person|
  person.age = 32
  person.grow_older
}
#=> #<Person:0x28347c4 @age=33, @name=:gavin>

···

On May 10, 4:21 pm, MenTaLguY <men...@rydia.net> wrote:

On Fri, 11 May 2007 07:06:29 +0900, Vasco Andrade e silva <vasc...@gmail.com> wrote:

> By the way are class_eval, module_eval, instance_eval and instance_exec
> the only exceptions?

In Ruby's core library, yes. It's possible to implement new methods with similar behavior
(which is occasionally useful), but that isn't the norm.

Don't forget define_method .

···

On 5/10/07, MenTaLguY <mental@rydia.net> wrote:

On Fri, 11 May 2007 07:06:29 +0900, Vasco Andrade e silva <vascoas@gmail.com> wrote:

> By the way are class_eval, module_eval, instance_eval and instance_exec
> the only exceptions?

In Ruby's core library, yes. It's possible to implement new methods with similar behavior (which is occasionally useful), but that isn't the norm.

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

MenTaLguY wrote:

In Ruby's core library, yes. It's possible to implement new methods
with similar behavior (which is occasionally useful), but that isn't the
norm.

-mental

How can i do that?

I was thinking.. If I want to "bind" self to yield context, with 0
params, i can use a solution like this one:

def create( name, &block )
person = Person.new( name )
person.instance_eval( &block )
p person
end

person.instance_eval( &block ) # some kind of yield(self) inside
instance_eval

but what if i want yield with params, and still have self like
instance_eval?

Example:
class A
  def some_method(&block)
    yield(:arg1, :arg2)
  end
end
a = A.new
# wanted: self "equals" to a
a.some_method { |arg1, arg2| p self }

Vasco A. Silva

···

--
Posted via http://www.ruby-forum.com/\.

Here's a real-world example of a DSL I created at work:

bp( 9 ){
  lopa( '02' ){
    sb "New Project Workflow.ppt"
      cr 1331

    sb "Add to Online Repository.ppt"
      crs 2216, 3560
      keywords "Workspace", "Phase 2"
  }
}

For both blocks, the function creates an instance of a particular
class and then uses instance_eval to ensure that the methods
referenced within that block are called on the appropriate object. If
I had not mucked about with the self inside the blocks, I would have
had to write something like:

bp( 9 ){ |blockpoint|
  blockpoint.lopa( '02' ){ |section|
    section.sb "New Project Workflow.ppt"
      section.cr 1331

    section.sb "Add to Online Repository.ppt"
      section.crs 2216, 3560
      section.keywords "Workspace", "Phase 2"
  }
}

···

On May 10, 4:50 pm, Phrogz <g...@refinery.com> wrote:

Using instance eval makes some DSLs (domain specific languages) easier
to create, rather than having to use the object yielded to the block
in every call.

Now this is really *ugly*, but maybe you can make it less ugly?

class A
  def a &blk
    blk.call self, 42
  end
end

A.new.a { |o,x| puts "#{self}: #{x}" }
A.new.a { |o,x| o.instance_eval{puts "#{self}: #{x}"} }

HTH
Robert

···

On 5/17/07, Vasco Andrade e Silva <vascoas@gmail.com> wrote:

MenTaLguY wrote:
> In Ruby's core library, yes. It's possible to implement new methods
> with similar behavior (which is occasionally useful), but that isn't the
> norm.
>
> -mental

How can i do that?

I was thinking.. If I want to "bind" self to yield context, with 0
params, i can use a solution like this one:

>def create( name, &block )
> person = Person.new( name )
> person.instance_eval( &block )
> p person
>end

person.instance_eval( &block ) # some kind of yield(self) inside
instance_eval

but what if i want yield with params, and still have self like
instance_eval?

Example:
class A
  def some_method(&block)
    yield(:arg1, :arg2)
  end
end
a = A.new
# wanted: self "equals" to a
a.some_method { |arg1, arg2| p self }

Vasco A. Silva

--
Posted via http://www.ruby-forum.com/\.

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

Hi --

MenTaLguY wrote:

In Ruby's core library, yes. It's possible to implement new methods
with similar behavior (which is occasionally useful), but that isn't the
norm.

-mental

How can i do that?

I was thinking.. If I want to "bind" self to yield context, with 0
params, i can use a solution like this one:

def create( name, &block )
person = Person.new( name )
person.instance_eval( &block )
p person
end

person.instance_eval( &block ) # some kind of yield(self) inside
instance_eval

but what if i want yield with params, and still have self like
instance_eval?

Example:
class A
def some_method(&block)
   yield(:arg1, :arg2)
end
end
a = A.new
# wanted: self "equals" to a
a.some_method { |arg1, arg2| p self }

That's actually what instance_exec does:

# Requires Ruby 1.9
class A
   def x(&block)
     instance_exec(1,2,&block)
   end
end

A.new.x {|a,b| p a, b, self }

# Output
   1
   2
   #<A:0xb7f00700>

I still don't know what the rationale is for the name, or how one is
supposed to know that instance_exec does it this way and instance_eval
does it the other way (except that I've been using instance_eval for
longer, but that won't help people who are just starting to learn
Ruby).

David

···

On Thu, 17 May 2007, Vasco Andrade e Silva wrote:

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

>
> > By the way are class_eval, module_eval, instance_eval and instance_exec
> > the only exceptions?
>
> In Ruby's core library, yes. It's possible to implement new methods with similar behavior (which is occasionally useful), but that isn't the norm.

Don't forget define_method .

You are a genius Rick!!!

So eventually I found what OP needs :wink:

class A
  def a &blk
    i = 1
    m = methods
    i += 1 while methods.include? "x#{i}"
    self.class.send :define_method, "x#{i}", &blk
    send "x#{i}", 42
    self.class.send :remove_method, "x#{i}"
  end
end

a = A.new
a.a {|p| puts "#{self}: #{p}"}
puts a.methods

Probably worth looking into Mauricios Eigenklass. He probably did it
much better maybe caching the method (no idea how to avoid potential
conflicts) ...

Cheers
Robert

···

On 5/11/07, Rick DeNatale <rick.denatale@gmail.com> wrote:

On 5/10/07, MenTaLguY <mental@rydia.net> wrote:
> On Fri, 11 May 2007 07:06:29 +0900, Vasco Andrade e silva <vascoas@gmail.com> wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

--
You see things; and you say Why?
But I dream things that never were; and I say Why not?
-- George Bernard Shaw

I agree with you (Gavin Kistner). The question is, what could you loose
if self was always set as it is with class_eval, instance_eval, etc.?
You could still do:

def create( name )
person = Person.new( name )
yield person
p person
end

create( :gavin ){ |person|
person.age = 32
person.grow_older
}

as all the other things.

For me the question is: What's the purpose of not always setting self to
yield context?

Vasco A. Silva

···

--
Posted via http://www.ruby-forum.com/\.

> I was thinking.. If I want to "bind" self to yield context, with 0
> params, i can use a solution like this one:
>
>> def create( name, &block )
>> person = Person.new( name )
>> person.instance_eval( &block )
>> p person
>> end
>
> person.instance_eval( &block ) # some kind of yield(self) inside
> instance_eval
>
> but what if i want yield with params, and still have self like

That's actually what instance_exec does:

# Requires Ruby 1.9
class A
   def x(&block)
     instance_exec(1,2,&block)
   end
end

Or in Ruby 1.8.x you can use Mauricio's version:
http://eigenclass.org/hiki/bounded+space+instance_exec

I still don't know what the rationale is for the name, or how one is
supposed to know that instance_exec does it this way and instance_eval
does it the other way (except that I've been using instance_eval for
longer, but that won't help people who are just starting to learn
Ruby).

I'm not exactly sure where the name came from. Matz mentioned it in
his RubyConf 2005 Keynote, but it seems that he got the idea, (and the
name?) from someone posting on ruby-talk It only shows up as a
one-line item on one of his last charts.
http://glu.ttono.us/articles/2005/10/16/matzs-keynotes

_why gave an implementation here:
http://redhanded.hobix.com/inspect/aBlockCostume.html

This seems a little more naive since it always uses the same name for
the method :_cloaker, and it's not thread-safe.

ActiveSupport in Rails defines Object#instance_exec, but I'm not sure
if this was the chicken or the egg. This implementation uses a similar
technique of defining a method with the proc as the body, rails uses a
timestamp to make the method name 'unique.'

Mauricio's first implementation was a bit more sophisticated in that
it was thread-safe, but it didn't work with immediate value objects
like FixNums.

Mauricio came up with a second version which worked with these, this
version had a memory leak, leading to the latest version.

So that's the history of instance_exec as far as I've been able to
quickly ascertain.

Personally I'd prefer it if instance_exec were used to do this so that

  instance_exec(1, 2) {|a, b| ....}

would pass 1 and 2 as the arguments to the block. Perhaps it was felt
that this would lead to confusion with the current definition which
either takes arguments (a string and optional file name and line
number) OR a block, but not both.

···

On 5/17/07, dblack@wobblini.net <dblack@wobblini.net> wrote:

On Thu, 17 May 2007, Vasco Andrade e Silva wrote:

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/

Hi --

···

On Fri, 11 May 2007, Vasco Andrade e silva wrote:

I agree with you (Gavin Kistner). The question is, what could you loose
if self was always set as it is with class_eval, instance_eval, etc.?
You could still do:

def create( name )
person = Person.new( name )
yield person
p person
end

create( :gavin ){ |person|
person.age = 32
person.grow_older
}

as all the other things.

For me the question is: What's the purpose of not always setting self to
yield context?

Why constrain it to be one way or the other, instead of being able to
do either? Besides, I want to be able to do this:

   @x = 1
   some_method {|n| puts n + @x }

and not have it be some other object's @x.

David

--
Q. What is THE Ruby book for Rails developers?
A. RUBY FOR RAILS by David A. Black (http://www.manning.com/black\)
    (See what readers are saying! http://www.rubypal.com/r4rrevs.pdf\)
Q. Where can I get Ruby/Rails on-site training, consulting, coaching?
A. Ruby Power and Light, LLC (http://www.rubypal.com)

Why constrain it to be one way or the other, instead of being able to
do either? Besides, I want to be able to do this:

  @x = 1
  some_method {|n| puts n + @x }

and not have it be some other object's @x.

David

Excellent!! Your post said everything!
I couldn't be more agree (now)! (I can see the light now :wink: )
Thanks a lot!

Vasco A. Silva

···

--
Posted via http://www.ruby-forum.com/\.