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

Object orientation in es, and a bug?



(While preparing this message, I uncovered what appears to be a bug in
es.  I describe the bug at the end...)

A while back, when we discussed the (un)desirability of settor
functions in es, it was stated that they are used in ksh to support
object oriented programming and that perhaps they might be used for a
similar purpose in es.

However, once you have lambda, one can easily implement do some simple
o-o stuff.  For example, a simple stack object type (without error
checking) could be implemented as follows

  fn stack {
    let (s=
	 push=@ items{s=$items $s}
	 pop =@ {let (a=$s(1)) {s=$s(2 ...); result $a}}
	 all =@ {result $s})
      result @ method args{$$method $args}}

In other words, put the object's data in a let (or lambda) body and
provide a simple method dispatching routine (the @ method args
... thing).  This is easier in es than in (say) scheme, because in
scheme you would have to code the dispatch routine something like

  (lambda (method . args)
    (case method
      ((push) (apply push args))
      ((pop)  (apply pop  args))
      ((all)  (apply all  args))))

Here is a simple demonstration of the stack object type:

  ; f=<={stack}
  ; g=<={stack}
  ; $f push foo
  ; $g push grief!
  ; $f push fie foe
  ; $g push good
  ; $f push fee
  ; echo <={$f pop}
  fee
  ; echo <={$f pop}
  fie
  ; echo <={$f pop}
  foe
  ; echo <={$f pop}
  foo
  ; echo <={$g all}
  good grief!

So, indeed, simple object oriented programming is not hard to do in
es.  The cost in terms of memory appears to be high though.  After all
the pushing on $f and before the popping, we get

  ; 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}

(I reformatted the one line output using M-q in emacs...)

which does indeed appear to use an excessive amount of space.  Worse,
it becomes INCORRECT if passed through the environment to an inferior
es:

  ; es
  ; prompt = ';; ' ''
  ;; echo <={$f pop}
  fee
  ;; echo <={$f pop}
  fie
  ;; $f push poodle
  ;; echo <={$f all}
  fee fie foe foo

The problem seems to be that each interior function now has its own
copy of s, rather than referring to the common s.  Surely a bug?

- Harald