MOO-cows Mailing List Archive


RE: Operators

>> 1) I like the idea of having ++/-- because I frequently write statements
>> like count = count+1;

I should note, BTW that this sort of construction comes up much less
often in MOO than in C, given that MOO has a real FOR loop (i.e., as
opposed to C's "FOR" loop which is simply a variant of WHILE that
requires putting in the increment explicitly).

>>  and I'm lazy

I rest my case.  :)

>> 2) I don't really see the point in adding it to MOO, though.  If you're
>> going to add something at this point, add something that can't already be
>> done.  Of course, if you're creating a new system from scratch, then maybe
>> this is something worth including.

> I can.  Take this:

> foo = {"tom", "dick", "harry"};
> foo = {@foo, "jane"};

> goes and creates a whole new list, splices foo into it, and tacks on
> "jane".

> With something like this:

> foo @= "jane";
> (the operator appearance is just a suggestion, blame Tef for that) 

> foo only appears once.  Just directly assign to foo.

The questions of 
(1) how many times `foo' has to appear in the statement and 
(2) not having to actually copy the list that comprises the value of foo
are orthogonal.

In `foo = {@foo, "jane"}' it is not the reference to foo that requires
the copy (though this *used* to be the case in an older version of the
server, which would in fact do TWO copies of the list `foo' when
evaluating this statement), but rather the fact we're doing a list
modification at all.  This comes up even if we don't need any extra
space to append elements.  Consider

  foo[5] = "jane";

which may seem like it's modifying only element of foo.   In fact it's
copying the entire list, since it's really doing

  foo = listset(foo, "jane", 5);

This is due to the underlying semantics of MOO-code which doesn't allow
mutable values.  The only way to avoid the copy would be if the
reference count on the list argument to listset() dropped to 1,
indicating that no one else is referencing it; only in this case would
it be safe to do a destructive modify.  But, looking at the byte code,
we see (...simplifying things a bit...):

  PUSH foo
  PUSH "jane"
  PUSH 5
  CALL_FUNCTION 3 listset
  PUT foo

At the point of the call to listset, the reference count on the original
`foo' value is 2, since it is being referenced both by the variable
`foo' AND by the stack entry created by `PUSH foo'.  The information
that the variable `foo' is about to be re-assigned is just not available
to the interpreter at the point of the listset() call. 

To be sure, making this information available would be a fairly
straightforward optimization of the bytecode, e.g.,

  PUSH foo
  FREE foo   (== PUSH 0, PUT foo, POP)
  PUSH "jane"
  PUSH 5
  CALL_FUNCTION 3 listset
  PUT foo

but this requires an (admittedly trivial) dataflow analysis of the code
to establish that the value stored in `foo' at the beginning is not in
fact used by anything other than the listset call.

...however once you start talking about dataflow analysis and
rearranging the byte-code to reduce reference counts, you're essentially
talking about writing a byte-code compiler, however simple it might be,
and if you're going to do this (and can deal with the
storing/reconstituting-verb-source problem), the you may as well
implement some form of common-subexpression elimination, which will only
be marginally more trouble...  and then += and friends become totally
unnecessary, which was my original point.

Home | Subject Index | Thread Index