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

Allow a Callable for is default that will generate default values #6350

Open
p6rt opened this issue Jun 18, 2017 · 7 comments
Open

Allow a Callable for is default that will generate default values #6350

p6rt opened this issue Jun 18, 2017 · 7 comments
Labels

Comments

@p6rt
Copy link

@p6rt p6rt commented Jun 18, 2017

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

Searchable as RT131599$

@p6rt
Copy link
Author

@p6rt p6rt commented Jun 18, 2017

From @mscha

#!/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.

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jun 19, 2017

From @b2gills

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-archive.perl.org/perl6/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.

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jun 19, 2017

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

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jun 19, 2017

From @mscha

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​:

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-archive.perl.org/perl6/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.

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jun 19, 2017

From @zoffixznet

On Mon, 19 Jun 2017 09​:30​:41 -0700, brad wrote​:

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

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jul 18, 2018

From alastair.douglas@gmail.com

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.

Loading

@p6rt
Copy link
Author

@p6rt p6rt commented Jul 21, 2018

From @lizmat

FWIW, with​:

  http://modules.perl6.org/dist/Hash&#8203;::Restricted&#8203;:cpan&#8203;: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

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.

Loading

@p6rt p6rt added the RFC 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
Linked pull requests

Successfully merging a pull request may close this issue.

None yet
1 participant