Pass block instead of here document?

I'd rather pass in a block. Is there a way to do that? Something like:

<pseud-code>
module Kernel
    def tell(obj, &to_do)
       # what goes here?
    end
end

tell Foo.new do
    report
    eat 'burger', 'fries'
    drink 'beer'
    be_merry
end
</pseud-code>

def tell( obj, &to_do )
  obj.instance_eval( &to_do )
end

class Foo
  def say_hi
    p "Hi!"
  end
end

tell Foo.new do
  say_hi
end
#=> "Hi!"

···

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

It's really that easy? Amazing! Ruby makes things so easy compared with the other languages I've used that I'm constantly inventing hard ways of doing what is too obvious for me to see.

Thanks for your help.

Regards, Morton

···

On Oct 25, 2006, at 3:31 PM, Gavin Kistner wrote:

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

I'd rather pass in a block. Is there a way to do that? Something like:

<pseud-code>
module Kernel
    def tell(obj, &to_do)
       # what goes here?
    end
end

tell Foo.new do
    report
    eat 'burger', 'fries'
    drink 'beer'
    be_merry
end
</pseud-code>

def tell( obj, &to_do )
  obj.instance_eval( &to_do )
end

class Foo
  def say_hi
    p "Hi!"
  end
end

tell Foo.new do
  say_hi
end
#=> "Hi!"

Heck. Why bother with tell in the first place? Why not call instance_eval
directly?

--Ken

···

On Thu, 26 Oct 2006 04:31:31 +0900, Gavin Kistner wrote:

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

I'd rather pass in a block. Is there a way to do that? Something like:

<pseud-code>
module Kernel
    def tell(obj, &to_do)
       # what goes here?
    end
end

tell Foo.new do
    report
    eat 'burger', 'fries'
    drink 'beer'
    be_merry
end
</pseud-code>

def tell( obj, &to_do )
  obj.instance_eval( &to_do )
end

--
Ken Bloom. PhD candidate. Linguistic Cognition Laboratory.
Department of Computer Science. Illinois Institute of Technology.
http://www.iit.edu/~kbloom1/
I've added a signing subkey to my GPG key. Please update your keyring.

Hi --

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

I'd rather pass in a block. Is there a way to do that? Something like:

<pseud-code>
module Kernel
   def tell(obj, &to_do)
      # what goes here?
   end
end

tell Foo.new do
   report
   eat 'burger', 'fries'
   drink 'beer'
   be_merry
end
</pseud-code>

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

class Foo
def say_hi
   p "Hi!"
end
end

tell Foo.new do
say_hi
end
#=> "Hi!"

It's really that easy? Amazing! Ruby makes things so easy compared with the other languages I've used that I'm constantly inventing hard ways of doing what is too obvious for me to see.

It's easy, but it can also be a bit obfuscating. For example:

   class C
     def initialize(thing)
       @thing = thing
     end

     def tell(&block)
       instance_eval(&block)
     end
   end

   c = C.new("Hi")

   @thing = "Hello"
   c.tell do
     puts @thing # Hi
   end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

David

···

On Thu, 26 Oct 2006, Morton Goldberg wrote:

On Oct 25, 2006, at 3:31 PM, Gavin Kistner wrote:

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

My understanding of blocks is at best still very shakey, but is there a
reason in all these that something like

def tell
  yield self
end

would not have the desired effect.

Then with appropriate method missings etc you could call whatever you like
in the block. If the drink and eat methods are already defined in the
object, they would be called as appropriate.

so to use it.

obj = Foo.new
obj.tell do
  eat 'burger', 'fries'
  drink 'beer'
end

Is there a reason that this would not have the same effect as the
instance_eval methods?

Syntactic sugar. I guess I have a sweet tooth.

Regards, Morton

···

On Oct 25, 2006, at 8:45 PM, Ken Bloom wrote:

On Thu, 26 Oct 2006 04:31:31 +0900, Gavin Kistner wrote:

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

I'd rather pass in a block. Is there a way to do that? Something like:

<pseud-code>
module Kernel
    def tell(obj, &to_do)
       # what goes here?
    end
end

tell Foo.new do
    report
    eat 'burger', 'fries'
    drink 'beer'
    be_merry
end
</pseud-code>

def tell( obj, &to_do )
  obj.instance_eval( &to_do )
end

Heck. Why bother with tell in the first place? Why not call instance_eval
directly?

I would expect that behavior and, in the situation I'm dealing with, I think it's an acceptable trade-off.

Regards, Morton

···

On Oct 25, 2006, at 3:54 PM, dblack@wobblini.net wrote:

Hi --

On Thu, 26 Oct 2006, Morton Goldberg wrote:

On Oct 25, 2006, at 3:31 PM, Gavin Kistner wrote:

From: Morton Goldberg [mailto:m_goldberg@ameritech.net]

I'd rather pass in a block. Is there a way to do that? Something like:
<pseud-code>
module Kernel
   def tell(obj, &to_do)
      # what goes here?
   end
end
tell Foo.new do
   report
   eat 'burger', 'fries'
   drink 'beer'
   be_merry
end
</pseud-code>

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end
class Foo
def say_hi
   p "Hi!"
end
end
tell Foo.new do
say_hi
end
#=> "Hi!"

It's really that easy? Amazing! Ruby makes things so easy compared with the other languages I've used that I'm constantly inventing hard ways of doing what is too obvious for me to see.

It's easy, but it can also be a bit obfuscating. For example:

  class C
    def initialize(thing)
      @thing = thing
    end

    def tell(&block)
      instance_eval(&block)
    end
  end

  c = C.new("Hi")

  @thing = "Hello"
  c.tell do
    puts @thing # Hi
  end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

Greg Brown and I were playing around with a solution for the method call issue at RubyConf. Here's the code we came up with:

class C
   def initialize(thing)
     @thing = thing
   end

   attr_reader :thing

   def tell(&block)
     if block and block.arity == 1
       block[self]
     else
       instance_eval(&block)
     end
   end
end

def thing; "Hello" end

c = C.new("Hi")

c.tell do
   thing # => "Hi"
end

c.tell do |obj|
   thing # => "Hello"
   obj.thing # => "Hi"
end

I know people frown on the instance_eval() trick, but this seems to be less of a problem. You can just choose to use the variable when you need it.

Just a thought.

James Edward Gray II

···

On Oct 25, 2006, at 2:54 PM, dblack@wobblini.net wrote:

It's easy, but it can also be a bit obfuscating. For example:

  class C
    def initialize(thing)
      @thing = thing
    end

    def tell(&block)
      instance_eval(&block)
    end
  end

  c = C.new("Hi")

  @thing = "Hello"
  c.tell do
    puts @thing # Hi
  end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

Hi --

···

On Thu, 26 Oct 2006, Daniel N wrote:

My understanding of blocks is at best still very shakey, but is there a
reason in all these that something like

def tell
yield self
end

would not have the desired effect.

Then with appropriate method missings etc you could call whatever you like
in the block. If the drink and eat methods are already defined in the
object, they would be called as appropriate.

so to use it.

obj = Foo.new
obj.tell do
eat 'burger', 'fries'
drink 'beer'
end

Is there a reason that this would not have the same effect as the
instance_eval methods?

Yes: instance_eval temporarily changes "self", and that means that
bareword method calls like eat and drink will be directed to the Foo
object. Otherwise, it's just like doing:

   eat

in the middle of a program where you haven't defined an eat method.

David

--
                   David A. Black | dblack@wobblini.net
Author of "Ruby for Rails" [1] | Ruby/Rails training & consultancy [3]
DABlog (DAB's Weblog) [2] | Co-director, Ruby Central, Inc. [4]
[1] Ruby for Rails | [3] http://www.rubypowerandlight.com
[2] http://dablog.rubypal.com | [4] http://www.rubycentral.org

Hello All,

Sorry but I do not really understand the way instance_eval is working
in this sample:

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

I'am new to Ruby and Metaprogramming and this method is still obscure to me.
Can someone help ?
Thanks a lot,

Luc

James Edward Gray II wrote:

It's easy, but it can also be a bit obfuscating. For example:

  class C
    def initialize(thing)
      @thing = thing
    end

    def tell(&block)
      instance_eval(&block)
    end
  end

  c = C.new("Hi")

  @thing = "Hello"
  c.tell do
    puts @thing # Hi
  end

So you get some perhaps unwanted variable-shadowing, and similarly
with method calls.

Greg Brown and I were playing around with a solution for the method call issue at RubyConf. Here's the code we came up with:

class C
  def initialize(thing)
    @thing = thing
  end

  attr_reader :thing

  def tell(&block)
    if block and block.arity == 1
      block[self]
    else
      instance_eval(&block)
    end
  end
end

def thing; "Hello" end

c = C.new("Hi")

c.tell do
  thing # => "Hi"
end

c.tell do |obj|
  thing # => "Hello"
  obj.thing # => "Hi"
end

I know people frown on the instance_eval() trick, but this seems to be less of a problem. You can just choose to use the variable when you need it.

I dunno... the presence of "|obj|" changes the semantics of the rest of the block. It's so easy to comment out the |obj| and then suddenly methods are handled in a surprising way:

c.tell do |obj|
   thing # => "Hello"
end

c.tell do #|obj|
   thing # => "Hi"
end

Visually, it doesn't look like anything important has changed.

Seems like a bug magnet.

···

On Oct 25, 2006, at 2:54 PM, dblack@wobblini.net wrote:

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

James, why do people frown upon instance_eval? I know you cannot speak
for all people, but what are the reasons to avoid it?

My only guess is that it would be slower than calling the block
directly -- block[self] -- as you showed in the code example.

Thoughts?

TwP

···

On 10/25/06, James Edward Gray II <james@grayproductions.net> wrote:

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

Hi --

> My understanding of blocks is at best still very shakey, but is there a
> reason in all these that something like
>
> def tell
> yield self
> end
>
> would not have the desired effect.
>
> Then with appropriate method missings etc you could call whatever you
like
> in the block. If the drink and eat methods are already defined in the
> object, they would be called as appropriate.
>
> so to use it.
>
> obj = Foo.new
> obj.tell do
> eat 'burger', 'fries'
> drink 'beer'
> end
>
> Is there a reason that this would not have the same effect as the
> instance_eval methods?

Yes: instance_eval temporarily changes "self", and that means that
bareword method calls like eat and drink will be directed to the Foo
object. Otherwise, it's just like doing:

   eat

in the middle of a program where you haven't defined an eat method.

I'm a bit lost with that. I think I don't understand what is self inside
the block. In the case of

def tell
  yield self
end

obj = Foo.new
obj.tell do
  eat 'burger', 'fries'
  drink 'beer'
end

What is self inside the block?

···

On 10/26/06, dblack@wobblini.net <dblack@wobblini.net> wrote:

On Thu, 26 Oct 2006, Daniel N wrote:

Luc Juggery wrote:

Hello All,

Sorry but I do not really understand the way instance_eval is working
in this sample:

def tell( obj, &to_do )
obj.instance_eval( &to_do )
end

I'am new to Ruby and Metaprogramming and this method is still obscure to me.
Can someone help ?
Thanks a lot,

Look at it this way: The items inside the block are evaluated
in the context of obj, rather than that of the tell method.

For example:

def tell( obj, &to_do )
   p self
   obj.instance_eval( &to_do )
end

If the to_do block were to print self, it would be the
same as obj (and *different* from what was printed before
the instance_eval).

HTH,
Hal

the tk bindings work this way, and debugging can be frustrating:

   harp:~ > cat a.rb
   class C
     def a() :a end
     def c() :c end
     def m(&b) instance_eval &b end
   end
   def b() :b end

   p C.new.m{ mixed_scope = [a, b, c] }

   harp:~ > ruby a.rb
   [:a, :b, :c]

certainly has it's application though....

-a

···

On Thu, 26 Oct 2006, Tim Pease wrote:

On 10/25/06, James Edward Gray II <james@grayproductions.net> wrote:

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

James, why do people frown upon instance_eval? I know you cannot speak
for all people, but what are the reasons to avoid it?

My only guess is that it would be slower than calling the block
directly -- block[self] -- as you showed in the code example.

Thoughts?

--
my religion is very simple. my religion is kindness. -- the dalai lama

I have literally seen code like this:

   must_save = self
   whatever do
     # use must_save in here, even though self changed...
   end

This is a sign of instance_eval() gone wrong, and Ara showed other issues.

Many take this as a sign that you should never instance_eval() a block like this, but I think that's going a bit far. It's very handy in creating DSLs, for example.

James Edward Gray II

···

On Oct 25, 2006, at 10:32 PM, Tim Pease wrote:

On 10/25/06, James Edward Gray II <james@grayproductions.net> wrote:

I know people frown on the instance_eval() trick, but this seems to
be less of a problem. You can just choose to use the variable when
you need it.

James, why do people frown upon instance_eval? I know you cannot speak
for all people, but what are the reasons to avoid it?