At 06:47 01/05/2004 +0900, you wrote:
>On Sat, May 01, 2004 at 05:38:03AM +0900, Jean-Hugues ROBERT wrote:
> > At 03:45 01/05/2004 +0900, you wrote:
> > >Hi,
> > >
> > >I am currently hacking a Packrat parser just for fun. I need to mix
> > >values (like numbers, strings etc.) together with lazy values. I want to
> > >make processing these values as transparent as possible.
> > > [...]
> > >Any comments or suggestions?
> > >
> > >Regards,
> > >
> > >  Michael
> >
> > Comments ? Not much. Besides the fact that we both need some kind of a
> > Reference class to inherit from.
> >
> > You to do:
> > class LazyValue < Reference
> > ...
> >
> > Me to do:
> > class LogicVariable < Reference
> >
> > In both cases we want automatic dereferencing of the object when its
> > value is required.
>
>Something like the Delegator class in delegate.rb is useful.
>I wrote my own lazy version:
>
>   class Lazy
>     self.methods.reject{|m| m =~ /^__(.*)__$/}.each {|m|
>       eval "def #{m}(*args, &block) __getobj__.send(:'#{m}', *args, 
> &block) end"
>     }
>
>     def initialize(*args, &block)
>       raise "no block given" if block.nil?
>       @args, @block = args, block
>     end
>
>     def __getobj__
>       if @block
>         @value = @block.call(*@args)
>         @block = @args = nil
>       end
>       return @value
>     end
>
>     def marshal_dump
>       __getobj__
>     end
>
>     def marshal_load(obj)
>       @value = obj
>     end
>
>     def method_missing(id, *args, &block)
>       __getobj__.send(id, *args, &block)
>     end
>   end

If this is not transparent, this is very close to transparent !

If I understand the code correctly, an instance of class Lazy delegates
to self.__getobj__() everything. I guess that besides the fact the only the 
Lazy
object itself implements :__getobj__, the key difference is the fact that
the object ids are different, but you can't tell because object_id() gets
delegated too (however __id__() can tell and __send__() is still there for
whatever reason I need to figure out).

This for sure works for Lazy, Future (Promise in some languages, Defered
in some others) and any other read-only cases. This is the rvalue case.

The lvalue case is another beast:
   def meth( x ) x = [x, "world"] end
   r = Refererence.new
   r = "Hello"
   meth( r, "World")
   p r # => Should be ["Hello", World]

Once solved I will be able to implement LogicVariable:
   v = LogicVariable.new
   v = free
   p match [[["x"]]], [[[v]]] # True
   p v # => "x", changed as a side effect of match
   v = "y"
   p match [[["x"]]], [[[v]]] # False, "x" != "y"
   p v # => "y", unchanged

As a reminder: I need LogicVariable to prototype a new "match" builtin
and its "assign" variation in an RCR. "assign" does what Ruby does
today in multiple assignments and when it assigns actual parameters
to formal ones (for method calls and proc calls), and more. "match"
does both assignment and comparison (when previous value already bound)

So far I implemented:
   v = LogicPointer.new
   v.free!
   p match [[["x"]]], [[[v]]] # True
   p v[] # => "x"
   v[] = "y"
   p match [[["x"]]], [[[v]]] # False
   p v[] # => "y"
Which is close, besides the additional []

Thanks to your code, I think I will be able to:
   v = LogicDelegator.new
   v.free!
   p match [[["x"]]], [[[v]]] # True
   p v[] # => "x"
   v[] = "y"
   p match [[["x"]]], [[[v]]] # False
   p v # => "y", note the absence of []
Which is one step in the good direction. Thanks.

>And to replace all Lazy objects with their values, I can now use
>obj = Marshal.load(Marshal.dump(obj)).

I am sorry but I am not familiar with Marshal much yet. I guess
you serializes and then rebuild the object, but I don't see the
magic to make that efficient (I assumed @value was serialized too)

> > As far as I know the least intrusive notation is to use the [] and []=
> > accessors that you can redefine. Be carefull with []=, the assigned
> > value is not under its control (use xx.[]= yy syntax instead).
>
>Hm, don't really understand that.

a = x[] = b # a == b, whatever the value returned by method x.[]=()
a = x.[]= b # a == value actually returned by method x.[]=()

> > I expect soon to have the issue striking again while implementing
> > "Future". Kind of lazy evaluation. A "Future" is the result of a
> > method call that is not available yet, but you don't mind, until
> > you need it, then you block until it is available. That is a
> > useful concept for distributed computing.
>
>Hm, sounds a bit like Oz :-) or similar to promises in E-lang?

I guess. There are multiple names for this concept.
http://www.c2.com/cgi/wiki?FutureObjects
I think its called Defered in Twisted. Future must have been the
first name, back in the mid 80s.

>Regards,
>   Michael

Thanks again.

Yours,

Jean-Hugues



-------------------------------------------------------------------------
Web:  http://hdl.handle.net/1030.37/1.1
Phone: +33 (0) 4 92 27 74 17