From: Jean-Hugues ROBERT Date: 2004-05-01T15:28:05+09:00 Subject: Re: def [](v) xx; return yy; end # returned value is ignored !? At 08:18 01/05/2004 +0900, you wrote: >On Apr 30, 2004, at 1:54 PM, Jean-Hugues ROBERT wrote: > >>That makes sense. Yet, I am missing the xxx= where I do control the value >>assigned to the lvalue. >>I am not alone. At this point there are multiple known cases where it >>would be needed for transparency: >> - Reference, a reference is an indirect mean of access to a lvalue's >> value that is dereferenced when the value is needed and that also makes >> it possible to assign a value to the lvalue at any time. >> - Lazy, a Lazy is a value that is computed when it is needed, not before. >> - Future, a Future is the returned value of an asynchronous method >> call that is waited for when it is needed, not before. >> - LogicVariable, a LogicVariable is a variable that can be free in >> addition to being bound to some value as regular variables are. > >I'm not sure what the problem is... What sort of circumstance will this >cause a problem? Perhaps you are thinking that assignment should do >something more than it was intended to. Something more than was intended, Yes, but only when the assignee is a Reference. This requires a change in Ruby implementation. What for ? A Lazy is a very good example: the invoked method does need not to know about it, it uses it as a regular object. In Ruby today, the invoked method needs to call some type of .value() checking first that something.kind_of? Lazy. Not very transparent. >Using your Pointer example, you could do this: > > p = Pointer.new() > x = p[] = "hello" > (p[] = "hello").inspect > >In line 2, would you expect something other than a simple "hello" string >to be assigned to x? something else ? No. However if p was a Reference, instead of a Pointer, I would expect x to be assigned p instead of "hello". >In line 3, would you expect #inspect to be called on p, rather than on the >assigned value? No. Your example of using a Pointer works today as it should. However, using a Reference instead of a Pointer, I would get rid of the [] and []= to achieve the same effect. >You say that these are 'known cases', quite possibly I am ignorant about >this, but I don't see how you couldn't have an object that computes it's >value only when requested, and how assignement would be at fault. Maybe a >short example of a problem-causing situation would help. The issue is about "when requested". With a pointer it is when .[]() is called. With a Reference is it transparent, p() get the value when it needs it (when it uses it), it does not care about whether its parameter is a Reference or not. >--Mark For sure some example is welcome, here is one, about the difference between a Pointer (that you can implement decently in Ruby today) and a Reference (that requires a change in the Ruby interpretor) and how a Reference makes a transparent Lazy possible. In this context I assume that the definition of a Reference is something like: A Reference is like a Pointer that is automatically dereferenced to access the underlying value. p = Pointer.new() # An anonymous Pointer, it holds the value itself. x = p[] = "hello" (p[] = "hello").inspect meth_by_ref( p) p[].inspect # => ["hello","world"] p = meth_by_val( p[]) p.inspect # => ["hello", "world"] ... def meth_by_ref( x ) x[] = [x[],"world"] end def meth_by_val( x ) [x, "world"] end A Pointer object requires explicit syntax to access the underlying value: syntax "ptr[]" means "content of ptr". syntax "ptr[] = xx" means "the content of ptr is assigned the value of xx" --- r = Reference.new() # An anonymous Reference, it holds the value itself. r = "hello" r.inspect meth( r) r.inspect # => ["hello", "world"] ... def meth( x ) x = [x, "world"] end Result: Thanks to Reference a method can change the value of a non local lvalue if it is provided a Reference to an object instead of the object itself. Yet, it can work with plain direct objects too. It is up to the caller to decide. As of today there is no way to implement the Reference class in Ruby. I hope this example gives you some insight of what can be done with a Reference and how it can help reduce the code size sometimes: class Lazy < Reference attr: block attr: ready def initialize( &ablock ) @ready = false @block = ablock end def getter() # gets called at runtime when Reference's value is needed if !@ready then setter( @block.call()) @ready = true end super() end def setter(x) # gets called at runtime when assigning to a Reference object super(x) unless @ready raise "not supported, read only" end end v = long_method() p v v = Lazy.new { long_method() } p v Expected behaviour: Without Lazy, long_method() is invoked immediatly With Lazy, long_method() is invoked when value is needed by p() The Key Point: p() does not need to know about that. Nota: getter()/setter() are bad names, some better scheme need to be designed You may note the similarity with the "proxy" pattern, as applied to Remote Objects: existing code keeps working for remote objects as it used to work for local ones, it is transparent. Reference provides a similar benefit for lvalues. Yours, Jean-Hugues ------------------------------------------------------------------------- Web: http://hdl.handle.net/1030.37/1.1 Phone: +33 (0) 4 92 27 74 17