Forum: Ruby self in blocks

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
C8e99ac7c04f239eff3c413a972f9ae8?d=identicon&s=25 Vasco Andrade e Silva (vascoas)
on 2007-05-10 23:37
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
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-10 23:42
(Received via mailing list)
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?

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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-10 23:46
(Received via mailing list)
Hi --

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

> # 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
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-05-10 23:49
(Received via mailing list)
On May 10, 2007, at 5:37 PM, Vasco Andrade e silva wrote:
> # 1)
> # output A
> A.class_eval { puts self }

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
C8e99ac7c04f239eff3c413a972f9ae8?d=identicon&s=25 Vasco Andrade e Silva (vascoas)
on 2007-05-11 00:06
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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-11 00:12
(Received via mailing list)
Hi --

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

> 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" :-)


David
912c61d9da47754de7039f4271334a9f?d=identicon&s=25 MenTaLguY (Guest)
on 2007-05-11 00:22
(Received via mailing list)
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.

-mental
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-05-11 00:55
(Received via mailing list)
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.

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>
852a62a28f1de229dc861ce903b07a60?d=identicon&s=25 Gavin Kistner (phrogz)
on 2007-05-11 01:00
(Received via mailing list)
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.

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"
  }
}
C8e99ac7c04f239eff3c413a972f9ae8?d=identicon&s=25 Vasco Andrade e Silva (vascoas)
on 2007-05-11 02:11
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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-11 02:15
(Received via mailing list)
Hi --

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

>>  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
C8e99ac7c04f239eff3c413a972f9ae8?d=identicon&s=25 Vasco Andrade e Silva (vascoas)
on 2007-05-11 02:23
>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 ;) )
Thanks a lot!

Vasco A. Silva
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-11 21:17
(Received via mailing list)
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.

Don't forget define_method .

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
C8e99ac7c04f239eff3c413a972f9ae8?d=identicon&s=25 Vasco Andrade e Silva (vascoas)
on 2007-05-17 05:31
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
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-17 12:12
(Received via mailing list)
On 5/17/07, Vasco Andrade e Silva <vascoas@gmail.com> wrote:
> params, i can use a solution like this one:
> but what if i want yield with params, and still have self like
> a.some_method { |arg1, arg2| p self }
>
> Vasco A. Silva
>
> --
> Posted via http://www.ruby-forum.com/.
>
>

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
1fba4539b6cafe2e60a2916fa184fc2f?d=identicon&s=25 unknown (Guest)
on 2007-05-17 14:07
(Received via mailing list)
Hi --

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

> params, i can use a solution like this one:
> but what if i want yield with params, and still have self like
> 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
8f6f95c4bd64d5f10dfddfdcd03c19d6?d=identicon&s=25 Rick Denatale (rdenatale)
on 2007-05-17 15:34
(Received via mailing list)
On 5/17/07, dblack@wobblini.net <dblack@wobblini.net> wrote:

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

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

--
Rick DeNatale

My blog on Ruby
http://talklikeaduck.denhaven2.com/
703fbc991fd63e0e1db54dca9ea31b53?d=identicon&s=25 Robert Dober (Guest)
on 2007-05-18 00:42
(Received via mailing list)
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:
> >
> > > 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 ;)

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
This topic is locked and can not be replied to.