Grubba and I started talking a bit about adding lvalues as an explicit
data type in Pike. I'll jot down what we arrived at for the record
(well, some of it are later thoughts by me):
An lvalue is a pointer to a variable that allows the variable to be
changed (as opposed to a pointer to a function). Generic variable
pointers could be implemented by adding two new svalue types: Pointer
to variable in object and pointer to variable in frame (if programs
get "proper" static variables in some future they would get this too).
The frame case is used for pointers to local variables in functions.
Refcounting in frames is already implemented for the sake of nested
functions, so returning a pointer to a local variable shouldn't be a
problem.
The solution with special pointer svalue types is better than the
double svalue (the thing to index followed by the index) approach
currently used internally for lvalues for two reasons: Firstly the
index operation is performed when the pointer is created instead of
when it's dereferenced, which trigs errors closer to the source.
Secondly it would avoid odd effects in various functions that doesn't
expect variable pointers.
Pointers to values in arrays, mappings and multisets don't need new
svalue types since their iterator objects can be used then (more on
that later).
Variable pointers would be used like in C. Silly example:
int append_to_buf (Stdio.File f, pointer(string) buf)
{
string in = f->read();
*buf += in;
return sizeof (in);
}
Some new operator lfuns would be needed:
&foo => Get the pointer to foo; calls `& in foo.
&foo->bar => Get the pointer to foo->bar; calls `&->("bar") in foo.
&foo[bar] => Ditto for []; calls `&[](bar) in foo.
`& and ``& already exist, so the first operator above would actually
become ```& with the current naming system. We're however
contemplating a new system with more verbose lfun names; `&this for
the new operator, `this&_ for `&, and `_&this for ``&.
The similarity between pointers and iterators is obvious, so iterators
should be able to act as pointers. To accomplish that an lfun
corresponding to the dereferencing * operator is necessary:
*foo => Gets the value the pointer points to; calls `*this in foo.
It's also interesting to have an lfun that returns a pointer svalue so
that it can be used in an lvalue context. An example:
for (pointer ptr = &my_obj[0]; *ptr; ptr++)
*ptr = reverse (*ptr);
^^^^
Here `&*this would be called to produce a pointer value which is
used as lvalue.
If `&*this returns an object instead of a basic pointer svalue,
`&*this would presumably be tried again, which would make it possible
to produce a infinite loop if `&*this should be silly enough to return
the iterator itself. A simple check for that might be a good idea.
To be symmetric with `[]= and `->=, one would add a `*this=_ instead
of `&*this. I do however like `&*this better since it's then possible
to do e.g.
*ptr += ({17});
with an efficient `+= operation without the need for a special
`*this+=_.
A `&*this lfun makes it possible to try it in any expression where no
better suited lfun is available:
foo + bar => Try: foo->`+(bar)
Then: bar->``+(foo)
Then: *(foo->`&*this) + bar
Then: foo + *(bar->`&*this)
That could be handy when implementing e.g. "smart" strings like
Locale.DeferredLocale. I don't know yet if it overall is a good idea
or not, though. It's clearly not a good idea in simple assignments and
arbitrary function calls.