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

%(), @(), $() are evil/weird #1946

Open
raiph opened this Issue Jun 21, 2018 · 12 comments

Comments

Projects
None yet
5 participants
@raiph
Contributor

raiph commented Jun 21, 2018

I thought I had filed something like the following as an issue before, or at least raised it, but I've failed thus far to find it. These really need to be known as evil/weird so at the risk of filing a duplicate...

Here's a design doc reference: http://design.perl6.org/S05#line_3070

%() is the worst.

'aa'  ~~    / . /; 
say %();

displays:

Map.new(())

And:

'aa'  ~~    / $\<foo\>=. /;
say %();

displays:

Map.new((foo => 「a」))

It doesn't expect the list that :g returns. It either gets confused:

'ab'  ~~ m:g/        . /; say %(); # {a => 「b」}

Or really confused:

'abc' ~~ m:g/ . /; say %(); # Odd number of elements found where hash initializer expected:
                            # Found 3 (implicit) elements:
                            # Last element seen:
                            # Match.new(list => (), made => Any, pos => 3, ...

Now let's really pile on.

Some are recommending %(...) as a best practice alternative to {...} as a hash constructor.

Docs even refer to %(...) as %().

Also, use of {} is slightly frowned upon as looking like an empty block -- and a natural inclination based on best practice comments is to use %(). Uhoh.

Worse, %() will sometimes actually return an empty hash -- when it doesn't return a populated read-only hash instead.

(I noticed someone somewhere wondering why the warning message on {} that said one should use %() instead was removed. Now you know why.)

Anyhow, %() is the most evil of these three.

@() is the least evil. It's an alias for the numbered sub-matches of $/.

'a' ~~ m:g/ . /; say @() =:= $/[]; # True

But it's still thoroughly weird.

Though not as weird as $(). That stores a copy of $/.ast.Str. If $/ is a list, it borks:

'a' ~~ m:g/ . /; say $()

displays

No such method 'ast' for invocant of type 'List'

@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 21, 2018

Member

Please just deprecate this.

IRC discussion.

Member

AlexDaniel commented Jun 21, 2018

Please just deprecate this.

IRC discussion.

@zoffixznet

This comment has been minimized.

Show comment
Hide comment
@zoffixznet

zoffixznet Jun 21, 2018

Contributor

These have been on the 6.d-prep chopping block for quite a while: https://github.com/perl6/6.d-prep/blob/master/TODO/FEATURES.md#remove--magicalness-from--and-

I thought I had filed something like the following as an issue before, or at least raised it, but I've failed thus far to find it.

It's https://rt.perl.org/Ticket/Display.html?id=131392

Contributor

zoffixznet commented Jun 21, 2018

These have been on the 6.d-prep chopping block for quite a while: https://github.com/perl6/6.d-prep/blob/master/TODO/FEATURES.md#remove--magicalness-from--and-

I thought I had filed something like the following as an issue before, or at least raised it, but I've failed thus far to find it.

It's https://rt.perl.org/Ticket/Display.html?id=131392

@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 21, 2018

Member

Please just deprecate this.

OK well… maybe it's not that easy if we want to allow %() to mean an empty hash. I'm actually not sure what's the easiest way out, but I'm convinced that the current behavior has to go.

Member

AlexDaniel commented Jun 21, 2018

Please just deprecate this.

OK well… maybe it's not that easy if we want to allow %() to mean an empty hash. I'm actually not sure what's the easiest way out, but I'm convinced that the current behavior has to go.

@JJ

This comment has been minimized.

Show comment
Hide comment
@JJ

JJ Jun 22, 2018

Contributor

So, let me see if I got all the facts lined up:

  • The behavior of %() and @() is going to be deprecated soon.
  • Right now, there's no way to declare an empty hash using just brackets. {} is ambiguous, and %() will depend on what $/ contains. Also, %(...) does not seem to work.
Contributor

JJ commented Jun 22, 2018

So, let me see if I got all the facts lined up:

  • The behavior of %() and @() is going to be deprecated soon.
  • Right now, there's no way to declare an empty hash using just brackets. {} is ambiguous, and %() will depend on what $/ contains. Also, %(...) does not seem to work.
@jnthn

This comment has been minimized.

Show comment
Hide comment
@jnthn

jnthn Jun 22, 2018

Member

{} always means an empty hash, so no ambiguity at all. In fact, there's also no formal ambiguity around whether {...] declares a block or hash in general: the compiler follows the same set of rules every time to make the decision, and the reader can do just the same. It's just that one has to remember the rules (first item must be a syntactic Pair or a variable with a % sigil, $_ must not be used even implicitly, no declarations should be made), and some folks wish for a form that's always a hash literal without having to remember the rules.

That form could be the coercion syntax %(...), which isn't too bad, but as this ticket notes, %() is currently assigned a different meaning, that is of dubious value, so the approach of using the coercion syntax as a general way to write a hash literal breaks down at that point. Deprecating that meaning would, in the long run (because this would be a multi-year process), let %() mean an empty...well, something hash-y, either Hash or Map. I don't think the %(...) coercion form was originally intended to become a widely used alternative to {...}, thus why it taking another meaning probably wasn't seen as a problem.

Of course, hash() and hash(a => 1, b => 2) is a sure bet, as is ().hash and (a => 1, b => 2).hash.

Member

jnthn commented Jun 22, 2018

{} always means an empty hash, so no ambiguity at all. In fact, there's also no formal ambiguity around whether {...] declares a block or hash in general: the compiler follows the same set of rules every time to make the decision, and the reader can do just the same. It's just that one has to remember the rules (first item must be a syntactic Pair or a variable with a % sigil, $_ must not be used even implicitly, no declarations should be made), and some folks wish for a form that's always a hash literal without having to remember the rules.

That form could be the coercion syntax %(...), which isn't too bad, but as this ticket notes, %() is currently assigned a different meaning, that is of dubious value, so the approach of using the coercion syntax as a general way to write a hash literal breaks down at that point. Deprecating that meaning would, in the long run (because this would be a multi-year process), let %() mean an empty...well, something hash-y, either Hash or Map. I don't think the %(...) coercion form was originally intended to become a widely used alternative to {...}, thus why it taking another meaning probably wasn't seen as a problem.

Of course, hash() and hash(a => 1, b => 2) is a sure bet, as is ().hash and (a => 1, b => 2).hash.

@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 22, 2018

Member

@jnthn while what you've said is true, maybe it's worth mentioning that in other cases {} can as well mean an empty block, like if True {}.

Member

AlexDaniel commented Jun 22, 2018

@jnthn while what you've said is true, maybe it's worth mentioning that in other cases {} can as well mean an empty block, like if True {}.

@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 22, 2018

Member

Same in the statement modifier form:

say do {} for ^5 # Nil Nil Nil Nil Nil, not empty hashes

EDIT: actually it's different here, see comment by @jnthn++ below.

Member

AlexDaniel commented Jun 22, 2018

Same in the statement modifier form:

say do {} for ^5 # Nil Nil Nil Nil Nil, not empty hashes

EDIT: actually it's different here, see comment by @jnthn++ below.

@jnthn

This comment has been minimized.

Show comment
Hide comment
@jnthn

jnthn Jun 22, 2018

Member

if True {}

Hah, I didn't even think about this case, because we're not even looking to parse a term in that construct. :)

Same in the statement modifier form:

say do {} for ^5 # Nil Nil Nil Nil Nil, not empty hashes

That's because the block was taken as the block for do. Add parens so that doesn't happen, and it's a Hash as expected

$ perl6 -e 'say do ({} for ^5)'
({} {} {} {} {})
Member

jnthn commented Jun 22, 2018

if True {}

Hah, I didn't even think about this case, because we're not even looking to parse a term in that construct. :)

Same in the statement modifier form:

say do {} for ^5 # Nil Nil Nil Nil Nil, not empty hashes

That's because the block was taken as the block for do. Add parens so that doesn't happen, and it's a Hash as expected

$ perl6 -e 'say do ({} for ^5)'
({} {} {} {} {})
@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 22, 2018

Member

Hah, I didn't even think about this case, because we're not even looking to parse a term in that construct. :)

Correct, which is why I said “other cases”. I guess my point is that there is some perceived ambiguity, especially if you're just starting out with the language (even though for the compiler that is not an issue).

That's because the block was taken as the block for do

Ah. That's right.

Member

AlexDaniel commented Jun 22, 2018

Hah, I didn't even think about this case, because we're not even looking to parse a term in that construct. :)

Correct, which is why I said “other cases”. I guess my point is that there is some perceived ambiguity, especially if you're just starting out with the language (even though for the compiler that is not an issue).

That's because the block was taken as the block for do

Ah. That's right.

@raiph

This comment has been minimized.

Show comment
Hide comment
@raiph

raiph Jun 23, 2018

Contributor

Ah, so I had written something about this before (in the RT, which I'd failed to find). Thanks Zoffix several times over.

Everyone else, thank you too and I'm closing this on the basis it's fully covered by the existing RT and 6.d item and new issues to doc these three and to redo related style guide aspects.

Contributor

raiph commented Jun 23, 2018

Ah, so I had written something about this before (in the RT, which I'd failed to find). Thanks Zoffix several times over.

Everyone else, thank you too and I'm closing this on the basis it's fully covered by the existing RT and 6.d item and new issues to doc these three and to redo related style guide aspects.

@raiph raiph closed this Jun 23, 2018

@AlexDaniel

This comment has been minimized.

Show comment
Hide comment
@AlexDaniel

AlexDaniel Jun 23, 2018

Member

@raiph actually, I'll reopen this one and close the ticket on RT.

Member

AlexDaniel commented Jun 23, 2018

@raiph actually, I'll reopen this one and close the ticket on RT.

@raiph

This comment has been minimized.

Show comment
Hide comment
@raiph

raiph Jul 27, 2018

Contributor

(Apologies for the accidental close and noise.)

Contributor

raiph commented Jul 27, 2018

(Apologies for the accidental close and noise.)

@raiph raiph reopened this Jul 27, 2018

@zoffixznet zoffixznet removed their assignment Jul 28, 2018

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment