Skip Menu |
Report information
Id: 131599
Status: open
Priority: 0/
Queue: perl6

Owner: Nobody
Requestors: perl6 [at] mscha.org
Cc:
AdminCc:

Severity: (no value)
Tag: (no value)
Platform: (no value)
Patch Status: (no value)
VM: (no value)



From: Michael Schaap <perl6 [...] mscha.org>
Date: Sun, 18 Jun 2017 23:52:31 +0200
To: rakudobug [...] perl.org
Subject: [BUG] "my %hash is default([])" misbehaves
Download (untitled) / with headers
text/plain 704b
#!/usr/bin/env perl6 my %sum{Int} is default([]); %sum{4}.push: "1+3"; %sum{4}.push: "2+2"; say (1..10).grep(-> $i { %sum{$i} == 2 }); # Expected output: (4) # Actual output: (1 2 3 4 5 6 7 8 9 10) %sum{3}.push: "1+2"; say (1..10).grep(-> $i { %sum{$i} == 2 }); # Expected output: (4) # Actual output: () say %sum; # Expected output: {3 => [1+2], 4 => [1+3 2+2]} # Actual output: {} say %sum{4}; # Expected output: [1+3 2+2] # Actual output: [1+3 2+2 1+2] # Without "is default([])" it works fine, except that the "grep" complains # (rightly) about uninitialized values. # % perl6 --version # This is Rakudo version 2017.04.3 built on MoarVM version 2017.04-53-g66c6dda # implementing Perl 6.c.
From: Brad Gilbert <b2gills [...] gmail.com>
Date: Mon, 19 Jun 2017 11:30:12 -0500
Subject: Re: [perl #131599] [BUG] "my %hash is default([])" misbehaves
To: perl6-compiler [...] perl.org
Download (untitled) / with headers
text/plain 1.9k
There does appear to be a bug, but I'd argue that it is in your code. my %sum{Int} is default([]); That line of code sets the default for all elements when they are first accessed to the very same instance of an Array. Remove the `is default([])` To stop the warnings that would then happen you could use `andthen` say (1..10).grep(-> $i { %sum{$i} andthen $_ == 2 }); Or you could use `.elems` say (1..10).grep(-> $i { %sum{$i}.elems == 2 }); The way Moose in Perl 5 works around this is to give it a subroutine that will produce the value to set it to then rather than a value. (slight simplification) Basically Perl 6 dutifully did what you asked it to, and there currently isn't as far as I know, a way to do what you intended. So this isn't really a bug report, but a feature request. The new feature may very well use the same syntax you have provided. On Sun, Jun 18, 2017 at 4:52 PM, Michael Schaap <perl6-bugs-followup@perl.org> wrote: Show quoted text
> # New Ticket Created by Michael Schaap > # Please include the string: [perl #131599] > # in the subject line of all future correspondence about this issue. > # <URL: https://rt.perl.org/Ticket/Display.html?id=131599 > > > > #!/usr/bin/env perl6 > > my %sum{Int} is default([]); > %sum{4}.push: "1+3"; > %sum{4}.push: "2+2"; > > say (1..10).grep(-> $i { %sum{$i} == 2 }); > # Expected output: (4) > # Actual output: (1 2 3 4 5 6 7 8 9 10) > > %sum{3}.push: "1+2"; > > say (1..10).grep(-> $i { %sum{$i} == 2 }); > # Expected output: (4) > # Actual output: () > > say %sum; > # Expected output: {3 => [1+2], 4 => [1+3 2+2]} > # Actual output: {} > > say %sum{4}; > # Expected output: [1+3 2+2] > # Actual output: [1+3 2+2 1+2] > > # Without "is default([])" it works fine, except that the "grep" complains > # (rightly) about uninitialized values. > > # % perl6 --version > # This is Rakudo version 2017.04.3 built on MoarVM version > 2017.04-53-g66c6dda > # implementing Perl 6.c.
From: Michael Schaap <perl6 [...] mscha.org>
Date: Mon, 19 Jun 2017 20:35:59 +0200
To: perl6-bugs-followup [...] perl.org
Subject: Re: [perl #131599] [BUG] "my %hash is default([])" misbehaves
Download (untitled) / with headers
text/plain 2.2k
Thanks for explaining, I see why it does what it does now, more or less. Using .elems is an elegant workaround. But if not a bug, I'd say it's at least an LTA; Rakudo should warn that you're shooting yourself in the foot. On 19-Jun-17 18:30, Brad Gilbert via RT wrote: Show quoted text
> There does appear to be a bug, but I'd argue that it is in your code. > > my %sum{Int} is default([]); > > That line of code sets the default for all elements when they are first accessed > to the very same instance of an Array. > > Remove the `is default([])` > > To stop the warnings that would then happen you could use `andthen` > > say (1..10).grep(-> $i { %sum{$i} andthen $_ == 2 }); > > Or you could use `.elems` > > say (1..10).grep(-> $i { %sum{$i}.elems == 2 }); > > The way Moose in Perl 5 works around this is to give it a subroutine that will > produce the value to set it to then rather than a value. (slight simplification) > > Basically Perl 6 dutifully did what you asked it to, and there currently > isn't as far as I know, a way to do what you intended. > > So this isn't really a bug report, but a feature request. > The new feature may very well use the same syntax you have provided. > > On Sun, Jun 18, 2017 at 4:52 PM, Michael Schaap > <perl6-bugs-followup@perl.org> wrote:
>> # New Ticket Created by Michael Schaap >> # Please include the string: [perl #131599] >> # in the subject line of all future correspondence about this issue. >> # <URL: https://rt.perl.org/Ticket/Display.html?id=131599 > >> >> >> #!/usr/bin/env perl6 >> >> my %sum{Int} is default([]); >> %sum{4}.push: "1+3"; >> %sum{4}.push: "2+2"; >> >> say (1..10).grep(-> $i { %sum{$i} == 2 }); >> # Expected output: (4) >> # Actual output: (1 2 3 4 5 6 7 8 9 10) >> >> %sum{3}.push: "1+2"; >> >> say (1..10).grep(-> $i { %sum{$i} == 2 }); >> # Expected output: (4) >> # Actual output: () >> >> say %sum; >> # Expected output: {3 => [1+2], 4 => [1+3 2+2]} >> # Actual output: {} >> >> say %sum{4}; >> # Expected output: [1+3 2+2] >> # Actual output: [1+3 2+2 1+2] >> >> # Without "is default([])" it works fine, except that the "grep" complains >> # (rightly) about uninitialized values. >> >> # % perl6 --version >> # This is Rakudo version 2017.04.3 built on MoarVM version >> 2017.04-53-g66c6dda >> # implementing Perl 6.c.
RT-Send-CC: perl6-compiler [...] perl.org
Download (untitled) / with headers
text/plain 423b
On Mon, 19 Jun 2017 09:30:41 -0700, brad wrote: Show quoted text
> Or you could use `.elems` > > say (1..10).grep(-> $i { %sum{$i}.elems == 2 });
PS: note that, as a general usecase, you also need a `:v` there. Otherewise you're .elems'ing an Any, which follows the anything-is-a-1-item-list rule and you end up with .elems being 1 for keys without values: my %h; say %h<meows>.elems 1 my %h; say %h<meows>:v.elems 0
Download (untitled) / with headers
text/plain 920b
On Mon, 19 Jun 2017 09:30:41 -0700, brad wrote: Show quoted text
> The way Moose in Perl 5 works around this is to give it a subroutine
Show quoted text
> there currently isn't as far as I know, a way to do what you intended.
I'd like this feature as well. I was in IRC asking about whether we could restrict a hash in the same way python does, such that %hash<missing-value> dies. It was noted that one can do my %h is default(Failure.new); This would put a Failure in anything that didn't exist, which would detonate whenever accessed. Presumably, this would be the same Failure each time, but that's probably OK. It means there is no way of generating a default based on access. I think that would look something like: my %h is default(-> $key { Failure.new("$key not provided") }); But then how would it know to run the Callable to generate the default, rather than simply providing the Callable as the default? I have no answer for that.
To: perl6-bugs-followup [...] perl.org
From: Elizabeth Mattijsen <liz [...] dijkmat.nl>
Subject: Re: [perl #131599] [RFC] Allow a Callable for `is default` that will generate default values
Date: Sat, 21 Jul 2018 08:56:58 +0200
Download (untitled) / with headers
text/plain 1.3k
FWIW, with: http://modules.perl6.org/dist/Hash::Restricted:cpan:ELIZABETH one can restrict access to a hash to a certain set of keys: use Hash::Restricted; my %h is restricted = a => 42, b => 666; # restrict to keys at initialization my %h is restricted<a b c>; # restrict to keys a, b, c Show quoted text
> On 18 Jul 2018, at 17:32, Alastair Douglas via RT <perl6-bugs-followup@perl.org> wrote: > > On Mon, 19 Jun 2017 09:30:41 -0700, brad wrote:
>> The way Moose in Perl 5 works around this is to give it a subroutine
>
>> there currently isn't as far as I know, a way to do what you intended.
> > I'd like this feature as well. I was in IRC asking about whether we could restrict a hash in the same way python does, such that %hash<missing-value> dies. > > It was noted that one can do > > my %h is default(Failure.new); > > This would put a Failure in anything that didn't exist, which would detonate whenever accessed. Presumably, this would be the same Failure each time, but that's probably OK. > > It means there is no way of generating a default based on access. I think that would look something like: > > my %h is default(-> $key { Failure.new("$key not provided") }); > > But then how would it know to run the Callable to generate the default, rather than simply providing the Callable as the default? I have no answer for that.


This service is sponsored and maintained by Best Practical Solutions and runs on Perl.org infrastructure.

For issues related to this RT instance (aka "perlbug"), please contact perlbug-admin at perl.org