On Thu Oct 16 06:31:14 2008, masak wrote:
> Here's a thorough investigation of the strange properties of %*ENV.

Here's an explanation -- I'll start with the summary first and then look
at the examples.

> In summary:
> 
> 1. Ordinary strings and strings in %*ENV are unequally treated. You
can call
> .trans(), or .trans([]) on the former, but you have to send in two non-
> invocant arguments to the latter.

Rakudo's %*ENV is simply an instance of Parrot's Env PMC.  Whenever we
fetch something from the Env PMC, we get back a String PMC.  This isn't
a full Rakudo Str object, though, so their behaviors are a bit latter.

In particular, Parrot's String PMC already has a .trans method defined
on it, so Rakudo's .trans method for Str doesn't override it.

> 2. The result of a successful .trans call on an %*ENV item returns
something
> which, when touched in any way, causes Rakudo to explode.

The .trans method on String PMC doesn't return a value at all -- it does
an inplace modification.  So, the return value is garbage that indeed
causes Parrot to go boom.

> 3. Actively modifying the %*ENV item using .=trans produces a Null PMC
> access
> in another Parrot sub, and doing this from within a subroutine, produces
> a Null
> PMC acces in yet another Parrot sub.

Since %*ENV returns a Parrot String PMC, and since the .trans method on
the String PMC returns garbage, the inplace modifier ends up trying to
store garbage back into the String PMC.

> 4. Setting an %*ENV item using infix:<=> has no effect. Setting it using
> infix:<:=> works. 

The values that come back from %*ENV are String PMCs that aren't tied to
the environment at all, thus assigning to those PMCs has no effect.

However, binding an item using <:=> does activate the set_*_keyed VTABLE
of the underlying Env PMC, so that does work.

> Setting %*ENV itself using infix:<=> produces a Parrot VM
> error.

The Env PMC is a singleton PMC that doesn't understand assignment. 
We'll need to map this somehow so that it understands how to rebuild
itself from a list or hash. 

> Setting it using infix:<:=> works. 

You can rebind %*ENV to a different hash, but then it loses its magical
Env properties.  (This may also end up being the case for infix:<=> above.)

> Assigning %*ENV to another
> variable
> using infix:<=> produces another Parrot VM error.

The Parrot Env PMC is a singleton PMC, so apparently there's not a way
to clone or copy it.  This will probably be fixed via ObjectRefs, if
it's not fixed already.

> 5. When calling the methods .keys, .values, .kv or .perl on %*ENV,
something
> fails with "No applicable methods". 

Since %*ENV (and the Env PMC) is not really a Hash or Mapping, none of
those methods yet apply.  This is probably fixable if we map the Env PMC
onto Rakudo's Mapping class.


So, with those points out of the way, here are the explanations of the
examples:


> say %*ENV<Q>.WHAT;
> # Str

%*ENV<Q> actually returns a Parrot String PMC, which we've mapped onto
the Rakudo Str type, so it reports 'Str' as its type (even though it isn't).

> say %*ENV<Q>.trans();
> # too few arguments passed (1) - 3 params expected

Since the String PMC has its own .trans method, the Str.trans method
doesn't get invoked (and the signatures are different).


> say %*ENV<Q>.trans( [], [] );
> # Null PMC access in get_string()
> say %*ENV<Q>.trans( [], [] ).WHAT;
> # Null PMC access in find_method()

This invocation matches the signature for String.trans (not Str.trans),
but that .trans is an inplace modification that returns PMCNULL.

> 
> %*ENV<Q> .= trans([ "A" => "B" ], [])'
> # Null PMC access in name()

This ends up calling %*ENV<Q>.trans( ... ), which returns PMCNULL and
cannot be assigned back to %*ENV<Q>.

> %*ENV<A> = "OH HAI"; say %*ENV<A>.perl
> # ""
> %*ENV<A> := "OH HAI"; say %*ENV<A>.perl
> # "OH HAI"

Assignment doesn't work, but binding does.



Hope this helps -- I'll see which of the above I can clean up.

Pm

Reply via email to