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