[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: Object orientation in es, and a bug?



>:> Yes, it's a documented bug that closures aren't preserved across es
>:> invocations.  That's because when a new shell starts up, it just has a
>:> bunch of environment strings with no indication that any of the closures
>:> they represent were shared originally.
>
>Yes, but I thought this only applied in cases like
>
>let (shared=....) {
>  fn fee ... {...}
>  fn fie ... {...}
>  fn foe ... {...}
>  fn foo ... {...} }
>
>where fee, fie, foe and foo have separate print representations that
>must become completely separate in the inferior shell.  But in my case
>I had only one global object possessing internal functions, and in
>this case I don't understand why what happened _must_ happen.

Well, if you look at the print representation you posted, it looked like:

  ; echo $f
  %closure(*=;s=fee fie foe foo;push='%closure(*=;s=fee fie foe foo)@
  items{s=$items $s}';pop='%closure(*=;s=fee fie foe
  foo;push=''%closure(*=;s=fee fie foe foo)@ items{s=$items $s}'')@ *
  {let(a=$s(1)){%seq {s=$s(2 ...)} {result $a}}}';all='%closure(*=;s=fee
  fie foe foo;push=''%closure(*=;s=fee fie foe foo)@ items{s=$items
  $s}'';pop=''%closure(*=;s=fee fie foe foo;push=''''%closure(*=;s=fee
  fie foe foo)@ items{s=$items $s}'''')@ * {let(a=$s(1)){%seq {s=$s(2
  ...)} {result $a}}}'')@ * {result $s}')@ method args{$($method) $args}

There are lots of "fee fie foe foo" closures that the subshell doesn't
realize are the same ones.

I think you can minimize this lossage by defining the stack as a procedure
in a closure with only a single lexically-scoped variable, that returns
message-passing procedures you can apply (got all that?).  Because you only
have one %closure() in the resulting string, there isn't a problem of
losing connectivity between closures (as long as you don't assign the stack
object to multiple variables).  This also avoids the exponential quoting
problem.

Note that the getters and setters are still lexically scoped although
they're a bit more cumbersome to access, so I defined some syntactic sugar
afterwards.

Hmm.  Does this implementation cause new getter/setter procedures to be
created each time the object is invoked?


    fn make-stack   stack {
        # comment this out if you want to be able to initialize the stack.
        stack=
        result { result (
                   # push
                   @ item { stack = $item $stack }

                   # pop
                   { 
                     let (a = $stack(1)) 
                       { 
                         stack = $stack(2 ...)
                         result $a
                       }
                   }

                   # all
                   { result $stack }
                 )
               }
    }

    fn push! obj args { let (fun = <={ $obj }) { $fun(1) $args } }
    fn pop!  obj      { let (fun = <={ $obj }) { $fun(2) } }
    fn all   obj      { let (fun = <={ $obj }) { $fun(3) } }

A demonstration:

    ; s = <={ make-stack }
    ; echo $s
    %closure(stack=){result @ item{stack=$item $stack} {let(a=$stack(1)){%seq {stack=$stack(2 ...)} {result $a}}} {result $stack}}
    ; push! $s a
    ; push! $s b
    ; push! $s c
    ; echo $s
    %closure(stack=c b a){result @ item{stack=$item $stack} {let(a=$stack(1)){%seq {stack=$stack(2 ...)} {result $a}}} {result $stack}}
    ; all $s
    # result 1 = c
    # result 2 = b
    # result 3 = a
    ; pop! $s
    # result = c
    ; all $s
    # result 1 = b
    # result 2 = a
    ; 

Kill me now.