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

temp with %hash<key> or @array[$i] produces unwanted artefacts #5420

Open
p6rt opened this issue Jul 5, 2016 · 6 comments
Open

temp with %hash<key> or @array[$i] produces unwanted artefacts #5420

p6rt opened this issue Jul 5, 2016 · 6 comments
Labels

Comments

@p6rt
Copy link

p6rt commented Jul 5, 2016

Migrated from rt.perl.org#128544 (status was 'open')

Searchable as RT128544$

@p6rt
Copy link
Author

p6rt commented Jul 5, 2016

From @zoffixznet

using `temp` on a hash key restores its original value when we leave the scope, while other keys are free to be modified​:

m​: my %h = foo => 'bar'; { temp %h<foo> = 'meow'; }; say %h
rakudo-moar d4ac15​: OUTPUT«{foo => bar}␤»

m​: my %h = foo => 'bar'; { temp %h<foo> = 'meow'; %h<not-foo> = 42; }; say %h
rakudo-moar d4ac15​: OUTPUT«{foo => bar, not-foo => 42}␤»

However, if the `temp`ed key did not exist in the original hash, it WILL exist after leaving the scope. Expected behaviour​: the key does not exist​:

m​: my %h = foo => 'bar'; { temp %h<not-foo> = 'meow'; }; say %h
rakudo-moar d4ac15​: OUTPUT«{foo => bar, not-foo => (Any)}␤»

This issue was originally mentioned in https://rt.perl.org/Ticket/Display.html?id=126447 and currently-fudged tests exist​: Raku/roast@9977e56

@p6rt
Copy link
Author

p6rt commented Jul 5, 2016

From @zoffixznet

This occurs for arrays too actually​:

m​: my @​a; { temp @​a[10] = "foo" }; dd @​a
rakudo-moar d4ac15​: OUTPUT«Array @​a = [Any, Any, Any, Any, Any, Any, Any, Any, Any, Any, Any]␤»

@p6rt
Copy link
Author

p6rt commented Aug 8, 2016

From @zoffixznet

Currently skipped spectests in place​: Raku/roast@0ec97817b7

@p6rt
Copy link
Author

p6rt commented Aug 8, 2016

From @smls

Seems like a dubious spectest to me. Are you sure that this is the intended behavior?

I mean, it's a desirable feature in and of itself, but I don't see how it can possibly work (in the general case), unless you extend the Perl 6 container system or severely restrict what kind of expressions `temp` accepts.

As it is now, `temp` accepts an arbitrary expression, and works fine as long as the expression ends up returning an rw container​:

  sub a0 is rw { @​array[0] }
  temp a0() = 42;

In fact, there's nothing fundamentally special, design wise, about the expression `@​array[$i]` - it's just a postcircumfix operator returning an rw container.

In any case, `temp` gets passed an rw container (i.e. a Scalar or Proxy) and has no idea if it came from an array/hash or not.
Unless I'm mistaken, the public interface of an rw container has just two operations​: "store" and "fetch".

This means that `temp` has to use "fetch" to remember the original value, "store" to override it with the replacement value, and then at the end of the block another "store" to restore the original value. I don't know of any public mechanism for `temp` to do a :delete operation on the array/hash from which the rw container originated, or even to know when it would need to do so.

Of course, `temp` could hack into the non-public internals of the special Scalar's that are returned by Array and Hash for nonexistent elements. But this would violate the Perl 6 design principle that the built-in data structure classes are not "special" or "hard-coded", i.e. that CPAN modules should be able to implement their own similar data structure classes in pure Perl 6 code and benefit from all the same things that the built-ins do (like postcircumfix []).

Another solution would be to no longer allow `temp` to accept a general Perl 6 expressions, and instead instruct the parser to expect a variable or variable-like construct to follow. But where do you draw the line, e.g. will `temp %hash<a>[0]` be allowed? And what if a CPAN module wants to add an alternative operator that should function like .[] or .{}?

TL;DR​: Unless I'm missing something obvious, this ticket is not just a [BUG] but an [RFC] involving larger design issues that would need TimToady to weigh in, or jnthn who implemented/(designed?) the current iteration of the container system.

It's possible that the least bad option is to simply accept that `temp` cannot restore the non-existence of array/hash elements.

@p6rt
Copy link
Author

p6rt commented Aug 9, 2016

From @zoffixznet

Thanks. I removed the tests (Raku/roast@25869ebe13 )

For the ticket itself, there was a discussion yesterday and while we may not do anything for the
arrays, there was some conversation on doing something for the keys, so I'm going to leave the ticket open for now.

Discussion​: http://irclog.perlgeek.de/perl6-dev/2016-08-08#i_12986816

@p6rt
Copy link
Author

p6rt commented Dec 19, 2016

From @ronaldxs

On Tue, 09 Aug 2016 08​:46​:30 -0700, cpan@​zoffix.com wrote​:

Thanks. I removed the tests
(Raku/roast@25869ebe13 )

For the ticket itself, there was a discussion yesterday and while we
may not do anything for the
arrays, there was some conversation on doing something for the keys,
so I'm going to leave the ticket open for now.

Discussion​: http://irclog.perlgeek.de/perl6-dev/2016-08-08#i_12986816

The IRC discussion seems to leave temp hash keys {temp %h<k>} as somewhat of an abstract concern but thought I might mention a substantial reason to leave the ticket open. This tick stems from an issue with %*ENV resolved with RT126447. I may be missing an implicit understanding of the effect on %*ENV but just in case ...

ron@​ron-laptop​:~$ perl -Mstrict -wE 'say "before"; system("printenv | grep -i none_such"); sub f { local $ENV{"none_such_$$"} = "marker"; say "during"; system("printenv | grep -i none_such")}; f(); say "after"; system("printenv | grep -i none_such")'
before
during
none_such_20493=marker
after

ron@​ron-laptop​:~$ perl6 -e 'say "before"; shell "printenv | grep -i none_such; exit 0"; sub f { temp %*ENV{"none_such_$*PID"} = "marker"; say "during"; shell "printenv | grep -i none_such; exit 0"}; f(); say "after"; shell "printenv | grep -i none_such; exit 0"'
before
during
none_such_20395=marker
after
none_such_20395=

Note that in the perl6 version printenv sees the undefined environment variable in "after".

I came across this ticket from researching what seems to be a related ticket RT125398

@p6rt p6rt added the Bug label Jan 5, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

1 participant