From: Jean-Hugues ROBERT Date: 2004-05-02T17:18:09+09:00 Subject: Re: Why no Proc##[]=() ? Why no Proc##replace() ? About class Proc; def []=(*args); self[*args] end end and the value of .replace() At 06:43 02/05/2004 +0900, you wrote: >I'm not sure what your proposal means. >If x is a Proc object, then > x[arg1, arg2, ...] >Means to call the code stored by the Proc with the specified arguments. >What would > x[arg1, arg2, ...] = val1, ... >Mean? In your example, we don't appear to be doing any actual assigning. >We're just moving an argument to the proc out of the []. So the following >would be equivalent: > x[a, b, c] > x[a, b] = c That is right. Then the block can act as a rvalue or a lvalue depending on how many parameters it receives. >I'm not sure why you would want to do that. Also, Proc objects are simply >wrappers around some code, so I see only two ways that x[*args] = b would >make any sense semantically: > 1) x[*args] returns some assignable value. But Ruby doesn't allow > overriding > of assignment, so that point is moot. > 2) x[*args] = c makes x contain new code somehow. But that doesn't make any > sense either, really. I agree that the notion of lvalue is not that obvious. A lvalue is simply something that can stand on the left side of an assignment =. lvalue = rvalue. That a variable can be a lvalue is rather obvious: l = x, @i = x, @@c = x, $G = x But a method call can be a lvalue too. a = [1,2,3] # lvalue is variable a a[3] = 4 # lvalue is a[3], Ruby turns that into a.[]=( 4). o.i = 4 # lvalue is o.i, Ruby turns that into a.i=( 4) What append if a is a Proc instead of an Array a = proc { |*args| p args } a[3] = 4 # Turned into a.[]=( 4) Now, because Proc's method []=(*args) is defined as self[*args], it is a[4] that is executed. Which is turned in a.call( 4). As a result, args in the proc becomes [4]. p a[] # Turned in a.[]() This is now the rvalue case, args in the proc will be []. So: depending on the length of args, the proc can determine the intend of the caller: please act as a rvalue, or please act as a lvalue. Of course, the caller can p a[4]. The intent is ambiguous. >Also, what would Proc#replace do? Replace the code to be executed? You can >just make a new Proc if you want to do that. The only reason that #replace >could be different is if it kept the original binding, which means that you >could make a proc in one scope that creates variables in a completely >different scope, which would probably be impossible to compile, among other >things. You are half right; it is true that the original binding matters but a "replaced" proc is not a new Proc, it's the same object, redefined. I would think that Proc#replace would do something similar to other implementation of replace: change the value of the object in place. a = "aaa" p a.object_id() a.replace "bbb" p a.object_id() # a still reference the same object a = "ccc" p a.object_id() # a references a new object Now, what is Proc#replace() useful for ? You can imagine multiple cases where the Proc itself wants to change its own definition. For example, imagine a Proc that caches its result: r = proc { x = long_method self.replace { x } x } r.call() # long_method called r.call() # cached result There are other ways to do this of course, without replace: p = proc { @x ||= long_method } or (needed if result can be nil) p = proc { @x = long_method unless defined? @x; @x } Now, which method is more efficient ? >Could you explain some more? Sure, just ask. >- Dan Yours, Jean-Hugues ------------------------------------------------------------------------- Web: http://hdl.handle.net/1030.37/1.1 Phone: +33 (0) 4 92 27 74 17