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

Maybe warn when thunking *.foo ~~ $bar constructs? #2086

Open
zoffixznet opened this issue Jul 17, 2018 · 12 comments
Open

Maybe warn when thunking *.foo ~~ $bar constructs? #2086

zoffixznet opened this issue Jul 17, 2018 · 12 comments
Labels
LTA Less Than Awesome; typically an error message that could be better RFC Request For Comments

Comments

@zoffixznet
Copy link
Contributor

Had the user wondering why subset Tuesday of Date where *.day-of-week ~~ 2; doesn't work as expected.

The reason is ~~ is not an op that gets closed over, so that where clause is actually a thunk that has a smartmatch inside of it, with the whatevercode being just an arg. This doesn't give an warnings or error and just gives False even when given correct date object.

Perhaps this case should warn, same as we warn in, for example { *.so } about "double closure"?

@zoffixznet zoffixznet added LTA Less Than Awesome; typically an error message that could be better RFC Request For Comments labels Jul 17, 2018
@tisonkun
Copy link
Contributor

hmm, * could either be a Whatever or a WhateverCode, is this the problem?

@ab5tract
Copy link
Collaborator

ab5tract commented Jul 18, 2018 via email

@zoffixznet
Copy link
Contributor Author

this issue is that creating subsets that don't have an actual Callable should be a compile-time error?

Nope. The issue is a WhateverCode inside a thunk should be a compile-time warning.

Does someone have an example of where a subset without a Callable is useful?

The where clause supports thunking, so there's an infinite number of examples really

  • where 42|5
  • where Int|Num
  • where 'meows'
  • 'where .is-prime`
  • ...

@b2gills
Copy link
Contributor

b2gills commented Jul 18, 2018

I think if this gets covered by a best practices book, it should tell you to use a literal or a statement rather than a Callable. It should also say to steer clear of writing a WhateverCode there.

subset Foo where 2 | 3;         # literal   (best - declarative)
subset Foo where $_ ~~ 2 | 3;   # statement (next best - same but less declarative)

subset Foo where {$_ ~~ 2 | 3} # block (ok - but best for long code)

subset Foo where * ~~ 2 | 3;    # WhateverCode (- easy to get wrong)

# These don't work because the first part is a WhateverCode,
# but the `~~` doesn't co-mingle with existing WhateverCodes.
# So they test if a WhateverCode smartmatches against 2|3.
# (Always False as WhateverCode doesn't do .Numeric)
subset Foo where *.Int ~~ 2 | 3;
subset Foo where +* ~~ 2 | 3;

Another reason against WhateverCode is that the following doesn't do what you might expect.
(What's interesting is that a new Perl 6 programmer will have a different expectation to a seasoned Perl 6 programmer, and they are both wrong.)

subset Bar where * > 5 && * < 10;

What it does is produce two WhateverCodes * > 5 and * < 10. Since the first is truish, it only uses * < 10.


One reason I say that a literal is better is because the code written is always used as the right side of ~~.
(At least theoretically)

# These are all functionally equivalent
subset Foo where  2 | 3;

subset Foo where {2 | 3};

subset Foo where  $_ ~~  2 | 3;
subset Foo where  $_ ~~ {2 | 3};
subset Foo where {$_ ~~  2 | 3 };

subset Foo where  $_ ~~  $_ ~~ 2 | 3;
subset Foo where  $_ ~~ {$_ ~~ 2 | 3};
subset Foo where {$_ ~~  $_ ~~ 2 | 3 };
subset Foo where {$_ ~~ {$_ ~~ 2 | 3}};

subset Foo where  $_ ~~  $_ ~~  $_ ~~ 2 | 3;
subset Foo where {$_ ~~ {$_ ~~ {$_ ~~ 2 | 3}}};

This is also part of the reason … ~~ True always returns True, and … ~~ False always returns False.


T.L.D.R.:

I think that any time that someone writes a WhateverCode in a subset and it doesn't get put into place as the matcher it should warn and indicate that it's best to use a literal, statement, or a block. (It may be useful to state that $_ is available.)

@zoffixznet
Copy link
Contributor Author

zoffixznet commented Jul 18, 2018

writes a WhateverCode in a subset

We should warn about WhateverCodes in thunks (even outside subsets), just as we warn about WhateverCodes in Blocks.

@b2gills
Copy link
Contributor

b2gills commented Jul 18, 2018

The reason I took a step away from disallowing WhateverCode entirely is someone might want to use * instead of $_ for looks.

About the only thing that I can come up with is using a specific comparison operator

subset Foo where  * eqvsubset Foo where $_ eqv

I can not come up with a better example that wouldn't use $_ twice.
Which is something that a WhateverCode wouldn't even work for.


I can see someone saying that a method call on $_ is ugly, and they want to use *.

subset Bar where $_.method() == 42;
subset Bar where  *.method() == 42;
subset Bar where   .method() == 42;

I now think that it should always at least warn on a WhateverCode in a where, that tells you to use $_.

And if you write a WhateverCode that doesn't get put into place as the matcher, that it should be a compiler error. As I don't think it's possible to do without getting it wrong.
subset Bar where * > 5 && * < 10;
(Obviously if it adds a significant amount of complexity to the compiler it wouldn't be worth adding)

In a future version, we may consider making a WhateverCode where a compiler error.
The only thing it does over anything else is change the looks of the code, slightly.

@zoffixznet
Copy link
Contributor Author

The only thing it does over anything else is change the looks of the code, slightly.

But where *.foo has a completely different meaning than where .foo that has nothing to do with looks:

$ perl6 -e 'class Foo { method foo { "x" } }; subset Z where .foo; say Foo ~~ Z'
False
$ perl6 -e 'class Foo { method foo { "x" } }; subset Z where *.foo; say Foo ~~ Z'
True

I don't know how we got from a suggestion of making the "double-dipped" WhateverCode warning in thunks consistent with Blocks, to outright banning an extremely common feature that's part of the 6.c specification, and making the language inconsistent in that where would only accept some Callables just in case someone doesn't know how a WhateverCode works.

@b2gills
Copy link
Contributor

b2gills commented Jul 18, 2018

That's because *.foo is going through another level of indirection.
Boolify it.

class Foo { method foo { "x" } }

subset Z where ?.foo;
say Foo ~~ Z; # True

@ab5tract
Copy link
Collaborator

ab5tract commented Jul 19, 2018 via email

@zoffixznet
Copy link
Contributor Author

zoffixznet commented Sep 26, 2018

Another user bitten by this issue and a bit of discussion here: http://colabti.org/irclogger/irclogger_log/perl6?date=2018-09-26#l39


00:28 | TimToady | but yeah, it's like the double closure warning
-- | -- | --
00:29 | TimToady | m: my $x = { *.abs == 42 }
00:29 | camelia | rakudo-moar 5a974cb9e: OUTPUT: «=== SORRY!=== Error while compiling <tmp>␤Malformed double closure; WhateverCode is already a closure without curlies, so either remove the curlies or use valid parameter syntax instead of *␤at <tmp>:1␤------> my $x = { *.abs == 42 } ⏏…»
00:29 | Zoffix | yeah
00:29 | TimToady | so there's some prior art there
00:30 | TimToady | in fact, I see that we make that one fatal

@2colours
Copy link
Contributor

Is there any reason why *.foo ~~ $bar couldn't just do the right thing?

I mean, it's not like that smartmatching with a literal WhateverCode instance is ever useful, and from all I know, "whatever currying" is merely a syntactic transformation. The expression that got transformed ought to contain the smartmatch as well - similarly to other "thunky" operators. This is something that seems achievable with RakuAST, isn't it?

@librasteve
Copy link

@2colours - I think that this ^^^ is best

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
LTA Less Than Awesome; typically an error message that could be better RFC Request For Comments
Projects
None yet
Development

No branches or pull requests

6 participants