Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Working with %*ENV in Rakudo is difficult #203

Closed
p6rt opened this issue Jul 30, 2008 · 12 comments
Closed

Working with %*ENV in Rakudo is difficult #203

p6rt opened this issue Jul 30, 2008 · 12 comments

Comments

@p6rt
Copy link

p6rt commented Jul 30, 2008

Migrated from rt.perl.org#57400 (status was 'resolved')

Searchable as RT57400$

@p6rt
Copy link
Author

p6rt commented Jul 30, 2008

From johan.viklund@ebc.uu.se

$ svn info | grep Revi
Revision​: 29869

This works

$ ./perl6 -e 'my %t = (); my %s=%t'

But this does not

$ ./perl6 -e 'my %s=%*ENV'
Parrot VM​: Can't turn to a singleton type!
current instr.​: 'parrot;Perl6Hash;infix​:=' pc 4699 (src/gen_builtins.pir​:3215)
called from Sub '_block11' pc 28 (EVAL_10​:17)
called from Sub 'parrot;PCT​::HLLCompiler;eval' pc 806 (src/PCT/HLLCompiler.pir​:481)
called from Sub 'parrot;PCT​::HLLCompiler;command_line' pc 1305 (src/PCT/HLLCompiler.pir​:708)
called from Sub 'parrot;Perl6​::Compiler;main' pc 14902 (perl6.pir​:172)
Segmentation fault (core dumped)

--
Johan Viklund

@p6rt
Copy link
Author

p6rt commented Oct 16, 2008

From @masak

Here's a thorough investigation of the strange properties of %*ENV.

Rakudo r31926 has an %*ENV variable which claims to be of Hash type, but
which behaves very non-hashlike when you poke it. Its hash values are
supposedly strings, but don't have the corresponding Str methods.

say 'a'.WHAT;
# Str

say 'a'.trans();
# a

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

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

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

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

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

sub foo($s is rw) { $s .= trans( [ 'a' => 'b' ], [] ) }
say foo( 'a' );
# b
say foo( %*ENV<Q> );
# Null PMC access in can()

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

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

%*ENV = {}
# Parrot VM​: Can't modify a singleton

%*ENV := {}; say %*ENV.perl
# {}

my %h = %*ENV
# Parrot VM​: Can't turn to a singleton type!

%*ENV.keys
%*ENV.values
%*ENV.kv
%*ENV.perl
# No applicable methods.

say %*ENV.elems
# 1

say %*ENV.join
# get_string() not implemented in class 'Env'

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.

2. The result of a successful .trans call on an %*ENV item returns something
which, when touched in any way, causes Rakudo to explode. Most likely a
Parrot
Null value. This is the case regardless of the value of the %*ENV item, and
regardless of whether it has been defined.

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.

4. Setting an %*ENV item using infix​:<=> has no effect. Setting it using
infix​:<​:=> works. Setting %*ENV itself using infix​:<=> produces a Parrot VM
error. Setting it using infix​:<​:=> works. Assigning %*ENV to another
variable
using infix​:<=> produces another Parrot VM error.

5. When calling the methods .keys, .values, .kv or .perl on %*ENV, something
fails with "No applicable methods". (Note, though, that this is
different from
the error message produced by calling a method that doesn't exist on Hash​:
"Method 'foo' not found for invocant of class 'Env'") The %*ENV.elems mehtod
always reports '1'. Calling %*ENV.join() produces an error message.

@p6rt
Copy link
Author

p6rt commented Oct 16, 2008

The RT System itself - Status changed from 'new' to 'open'

@p6rt
Copy link
Author

p6rt commented Nov 4, 2008

From @jnthn

On Thu Oct 16 06​:31​:14 2008, masak wrote​:

Here's a thorough investigation of the strange properties of %*ENV.
...
Some of this will be resolved, most likely, in upcoming container and
assignment changes. We will probably end up making this a kind of tied
hash. Anyway, will review this again after the aforementioned changes
are done.

Jonathan

@p6rt
Copy link
Author

p6rt commented Nov 11, 2008

From @pmichaud

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

@p6rt
Copy link
Author

p6rt commented Dec 24, 2008

From @cspencer

This patch maps %*ENV onto the Mapping interface, allowing the
fmt/keys/kv/pairs/values methods to work.

Please let me know if their are any issues to be corrected in it!

Thanks,

Cory

On Tue Nov 11 13​:59​:46 2008, pmichaud wrote​:

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

@p6rt
Copy link
Author

p6rt commented Dec 24, 2008

From @cspencer

env-mapping.patch
Index: src/classes/Mapping.pir
===================================================================
--- src/classes/Mapping.pir	(revision 34338)
+++ src/classes/Mapping.pir	(working copy)
@@ -34,11 +34,39 @@
 
 =cut
 
+.sub 'fmt' :method :multi('Env')
+    .param pmc format
+    .param string sep  :optional
+    .param int has_sep :opt_flag
+
+    if has_sep goto with_arg
+    
+  no_arg:
+    .tailcall self.'!fmt'(format)
+  
+  with_arg:	
+    .tailcall self.'!fmt'(format,sep)
+.end
+
 .sub 'fmt' :method :multi('Hash')
     .param pmc format
     .param string sep  :optional
     .param int has_sep :opt_flag
 
+    if has_sep goto with_arg
+
+  no_arg:
+    .tailcall self.'!fmt'(format)
+  
+  with_arg:	
+    .tailcall self.'!fmt'(format,sep)
+.end
+
+.sub '!fmt' :method
+    .param pmc format
+    .param string sep  :optional
+    .param int has_sep :opt_flag
+
     .local pmc it
     .local pmc rv
 
@@ -71,7 +99,15 @@
 
 =cut
 
+.sub 'iterator' :method :multi('Env')
+    .tailcall self.'!iterator'()
+.end
+
 .sub 'iterator' :method :multi('Hash')
+    .tailcall self.'!iterator'()
+.end
+
+.sub '!iterator' :method
     .local pmc it
     .local pmc rv
 
@@ -102,7 +138,15 @@
 
 =cut
 
+.sub 'keys' :method :multi('Env')
+    .tailcall self.'!keys'()
+.end
+
 .sub 'keys' :method :multi('Hash')
+    .tailcall self.'!keys'()
+.end
+
+.sub '!keys' :method
     .local pmc it
     .local pmc rv
 
@@ -130,7 +174,15 @@
 
 =cut
 
+.sub 'kv' :method :multi('Env')
+    .tailcall self.'!kv'()
+.end
+
 .sub 'kv' :method :multi('Hash')
+    .tailcall self.'!kv'()
+.end
+
+.sub '!kv' :method
     .local pmc it
     .local pmc rv
 
@@ -173,7 +225,15 @@
 
 =cut
 
+.sub 'pairs' :method :multi('Env')
+    .tailcall self.'!pairs'()
+.end
+
 .sub 'pairs' :method :multi('Hash')
+    .tailcall self.'!pairs'()
+.end
+
+.sub '!pairs' :method
     .tailcall self.'iterator'()
 .end
 
@@ -240,7 +300,15 @@
 
 =cut
 
+.sub 'values' :method :multi('Env')
+    .tailcall self.'!values'()
+.end
+
 .sub 'values' :method :multi('Hash')
+    .tailcall self.'!values'()
+.end
+
+.sub '!values' :method
     .local pmc it
     .local pmc rv
 

@p6rt
Copy link
Author

p6rt commented Dec 24, 2008

From @pmichaud

Instead of duplicating the method calls, a simpler approach might be
to create a Perl6Env class that has Env and Mapping as parents, then
change %*ENV to create a Perl6Env instead of a Env. This should
cause %*ENV to inherit all of Mapping's methods. (For other examples,
see how Mapping, List, and Complex are set up to inherit from Parrot
built-in PMC types.)

This might also make it easier for us to create proxies that do
the correct thing with the real environment when values are stored
into %*ENV.

Thanks!

Pm

On Wed, Dec 24, 2008 at 10​:19​:23AM -0800, Cory Spencer via RT wrote​:

This patch maps %*ENV onto the Mapping interface, allowing the
fmt/keys/kv/pairs/values methods to work.

Please let me know if their are any issues to be corrected in it!

Thanks,

Cory

On Tue Nov 11 13​:59​:46 2008, pmichaud wrote​:

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

@p6rt
Copy link
Author

p6rt commented May 3, 2009

From @ronaldxs

I felt two things were worthy of note at this point.

1) The original example that opened the ticket "my %s = %*ENV" now
seems to work and environment variables can subsequently be dumped from
%s.

2) There is a test for the original example that opened this ticket, as
well as other $*ENV related tests, in t/spec/S02-magicals/env.t. This
test file is not yet in spectest.data.

Work, however, remains to be done to make %*ENV more useful as pointed
out on IRC​: http://irclog.perlgeek.de/perl6/2009-05-03#i_1113499.

@p6rt
Copy link
Author

p6rt commented Sep 4, 2009

From @markjreed

%*ENV<PATH>.perl.say
"/sw/bin​:/sw/sbin​:/Users/mreed/bin​:/opt/local/bin​:/opt/mailman/bin​:/opt/local/aolserver/bin​:/opt/local/i386-apple-darwin9.1.0/bin​:/usr/local/bin​:/usr/bin​:/bin​:/usr/X11/bin​:/usr/sbin​:/sbin​:/etc​:/usr/local/lib​:/usr/lib"
for %*ENV.kv -> $k, $v { say "{$k}={$v}" }
[...snip...]
DISPLAY=
HOME=
PATH=
[...snip...]
%*ENV.values.perl.say
["", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "", "",
"", "", "", "", "", "", "", "", ""]

Regular hashes work fine​:

my %h = { 'a' => 1, 'b' => 2 }; %h.values.perl.say
[1, 2]

Verified present in b51d94.

--
Mark J. Reed <markjreed@​gmail.com>

@p6rt
Copy link
Author

p6rt commented Sep 5, 2009

From @pmichaud

Now fixed in 825074a. Thanks!

Pm

@p6rt
Copy link
Author

p6rt commented Sep 5, 2009

@pmichaud - Status changed from 'open' to 'resolved'

@p6rt p6rt closed this as completed Sep 5, 2009
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

1 participant