Eric Mahurin wrote:
> --- Robert Klemme <bob.news / gmx.net> wrote:
>
>>> define_method, instance_eval, class_eval, module_eval, and
>>> maybe others seem to have this special ability - rebind the
>>> meaning of self (but not locals) for a Proc.  This brings us
>>> back to the topic I talked about earlier - unbind/rebind procs.
>>> It would be nice if we could do the same thing to a Proc that
>>> these methods can do internally:
>>>
>>> aProc.rebind_self(obj) -> aNewProc # rebind what self is
>>>
>>> With this, "obj.instance_eval(&proc)" would be equivalent to
>>> "proc.rebind_self(obj).call".
>>
>> Why do you want rebind if the other approach is much simpler?
>>
>> #instance_eval *always* rebinds self (and only self).
>
> because you can get a handle on that rebound Proc.  You might
> want to pass it around or whatever.

I see.  Although I don't have a use case for this at hand and in fact
never missed that.  But that might be just my personal experience.

>>>  Other useful rebindings may be:
>>>
>>> aProc.rebind_locals(binding) -> aNewProc
>>> aProc.rebind_all(binding) -> aNewProc
>>> # replace local variables with their current values
>>> aProc.unbind_locals -> aNewProc
>>
>> When do you think will unbind_locals be useful?
>
> As a replacement for many string evals - which are ugly,
> inefficient, and possibly dangerous.  Many (most?) times that
> you need to eval a string it is because you need to pull in
> some local variables to help define the string to be evaled.
> Here is the first example of a string eval in the 1.8 library I
> found:
>
> for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
>                    LI OPTION tr th td ]
>     methods += <<-BEGIN + nO_element_def(element) + <<-END
>       def #{element.downcase}(attributes = {})
>     BEGIN
>       end
>     END
> end
> eval(methods)
>
> This could be replaced by:
>
> for element in %w[ HTML HEAD BODY P PLAINTEXT DT DD
>                    LI OPTION tr th td ]
>     define_method(element.downcase.to_sym ,
>         proc { |attributes={}|
>             nO_element_def(element)
>         }.unbind_locals # replace element with constant
>     )
> end
>
> Much cleaner, huh?

Not really (at least to my eyes).  Also, there are some issues:

 - I don't know what nO_element_def does exactly, but it will have to be
rewritten to not create a string with ruby code

 - Your version might be less efficient.

 - There might be subtle differences because "element" is pulled into the
closure

 - Also, unbind_locals will remove "element" from the procs bindings

>> A proc
>> typically needs some
>> of the variables bound.  As for the rebindings, I would
>> prefer a general
>> mechanism to transfer state from one binding to another.
>> Then one could
>> implement all your rebind* methods in terms of that general
>> mechanism plus
>> do more.  Alternatively one could think about conversion
>> methods Binding <->
>> Hash.
>
> Transferring locals might be pretty easy, but transferring the
> meaning of self would be more difficult, I think.  At least
> without making a new Binding (and then you'd still need a way
> to rebind it to the original proc).

Why do you think that self is special?  If there is a general mechanism to
transfer state (i.e. bindings) into a binding, any variable can be
rebound.  I imagine something like

proc.binding.bind(:self => whatever, :foo => "bar")
eval("self", proc.binding) # -> whatever
eval("foo", proc.binding) # -> "bar"

<snip/>

> Interesting.  I assumed that since
> class_eval/instance_eval/module_eval all returned the same
> "self" that they did the same thing.  The only difference I see
> is in "def <method> ...".  With class_eval, it defines instance
> methods and with instance_eval, it defines class methods.
> That's kind of strange.  Some kind of magic is going on here
> other than the changing of self.

Definitely.

> I was hoping that instance_eval could be used to define class
> methods using #define_method, but #define_method does the same
> with both - defines instance methods.  Anybody know of an
> equivalent to #define_method for making class methods?  I
> couldn't figure out any way to define a class method from a
> proc - just out of curiosity.

Since a class method is just an instance method of the class:

>> class Foo;end
=> nil
>> class <<Foo
>>   define_method(:bar) {"bar"}
>> end
=> #<Proc:0x10185860@(irb):7>
>>
?> Foo.bar
=> "bar"
>>

Thanks for the interesting exchange!

Kind regards

    robert