John M. Dlugosz wrote:
Now back to straightening out my misconceptions about scalars _always_
holding item containers. If $x is bound to an Array, for example, the
compiled code can't be doing the indirection innately.
So it follows that the method forwarding is a property of the object
that the method is originally called on. That is, the Scalar (and any
"tied" item container implementations) are written to forward all
methods to the contained object. The compiler sees $x.foo() and doesn't
know anything about $x other than that it's some object, so it codes a
message dispatch to it. If $x holds a normal object, the foo method
gets called via the normal dispatching rules. But Scalar implements
something that catches all methods and forwards them to the contained item.
I think that the implementation type of a Scalar can be compiled away
in almost all cases that involve getting the value. And even in lvalue
usage the only thing worth an actual runtime container is the type
constraint closure to call prior to storing the rvalue. So after a
$x = @a the scalar just contains the ID of the array object.
That would imply that if a scalar happened to contain another scalar, e.g.
my $x = Scalar.new;
($x is bound to a Scalar which contains a Scalar which contains undef)
then any method called on $x would trigger the same behavior when the
contained object gets it, and be forwarded all the way down, no matter
how many Scalars I nested in this manner.
Hmm, I think the Scalar class should not be available for generic
instanciation. Scalar variables are handled through built-in features
of the underlying engine and are optimized heavily. Arrays are handled
by the same built-in mechanism, that is e.g. registers in Parrot.
So how does VAR work? It can't just wrap another level around the
original object to cancel out the automatic indirection. It can't tell
the compiler to generate different code, since the code knows nothing
about this interesting property of scalars. Instead it must return a
proxy that knows how to trigger the actual methods on the scalar,
avoiding the forwarding behavior of normal method calls.
===> Is that right?
I would say no. The VAR instructs the compiler to use a special
interface of the underlying engine facility. The interesting thing
is that one needs VAR($x).readonly but can use @a.readonly directly.
I would opt for VAR(@a).readonly for symmetry. Or actually this VAR
interface should be all caps. Why should the Array class support a
.readonly method in the first place? The compiler knows the readonly
status of all variables from their lexically available definition!
So does the programmer if she bothers to look them up.
"The unavoidable price of reliability is simplicity" -- C.A.R. Hoare
"Simplicity does not precede complexity, but follows it." -- A.J. Perlis
1 + 2 + 3 + 4 + ... = -1/12 -- Srinivasa Ramanujan