http://www.perlmonks.org?node_id=1064427


in reply to Re^2: use feature 'postderef'; # Postfix Dereference Syntax is coming in 5.20 (++)
in thread use feature 'postderef'; # Postfix Dereference Syntax is coming in 5.20

Ah, @* looking like a global variable, I can see that objection. The prior proposals I saw used ->@ not ->@*. I didn't mind the addition of the '*' when I saw it (just recently) because it seemed borrowed from Perl 6. But I'd be happy to have the '*' dropped so long as that doesn't introduce parsing difficulties.

Note that $obj->$* even already had a meaning before this change. However, that meaning was quite useless (since $* is no longer supported).

Surely there are cases when the introduction of a temporary variable can aid clarity, but I don't think that is universally true and I don't think it should be required (in order to work around the incomplete nature of postfix dereferencing prior to this patch).

my @got = ExactlyWhatThisReturns( $exactly, $what, $it, $is, $based, $on, )->@*;

If the routine and each of the variables above have reasonable names, then I think assigning a name to the temporary reference would add absolutely zero clarity.

Similarly, I think it will quite often be the case that in a construct like:

my( $state, $zip ) = $user->GetAccount()->GetPriorOrder() ->GetShippingAddress()->@{ 'state', 'zip' };

having to make up a name for the second-to-last result in the chain would have dubious value in improving clarity (more like negative value).

- tye        

Replies are listed 'Best First'.
Re^4: use feature 'postderef'; # Postfix Dereference Syntax is coming in 5.20 (*)
by shmem (Chancellor) on Nov 26, 2013 at 17:04 UTC
    Ah, @* looking like a global variable, I can see that objection.

    No. No!

    1. My concern is that the @* %* $* constructs blur the lines between operators, sigils and special variables, which is not about globalness or localization, but about language.
    2. I am with demerphq on that: It breaks the original model of sigils completely. And more so if the thingy were just a blank @ sign.

    As for your examples: what BrowserUk wrote. I prefer the notation

    my( $state, $zip ) = @{ $user->GetAccount()->GetPriorOrder()->GetShippingAddress() }{ 'state', 'zip' };
    because I can read it immediately: a list of variables (my( $state, $zip )) get assigned a list context dereference of soemthing returned by a function call which happens to be a hash ref, and the returned values are accessed with the keys 'state' and 'zip'. Note that the first thing is list.

    And I deem this

    perl -le '%* = (foo => bar); print $*{foo}; @* = qw(foo bar baz); prin +t $*[1]'
    line's result to be two places where to go now and try to forget about perl, perl5, perl6, the Nikolaus Sieht Alles and whatever else rests heavily on my mind.

    perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
      Ah, @* looking like a global variable, I can see that objection.

      No. No!

      My concern is that the @* %* $* constructs blur the lines between operators, sigils and special variables, which is not about globalness or localization, but about language.

      I said "global variable" not to emphasize "global" (don't be so quick to assume I'm not agreeing with you?). I see the syntax having a strong visual similarity to a (global or "special") variable and find this similarity to be a problem (same as you). I don't like blurring the lines between what looks like a type of variable and what is a syntax used for dereferencing.

      I don't see how it blurs any lines related to operators, though. Unless you somehow consider something like ->{ ... } an operator. -> is an operator. ->[ is something more than that for which I don't have a particularly good name. ->[ ... ] is "syntax" or a "construct".

      So, clearly, we need to drop the % (modulo) operator since we all know that % is supposed to be a sigil, and we mustn't blur the lines between sigils and operators. Same goes for & and *, by the way. ** looks like a glob named '*' so certainly must not be used as an operator. %= looks like a special hash.

      Actually, %= is a global hash. It is also the modulo-assignment operator.

      > say '%= = 0..9; $k = %=; $k %= %=;' Argument "4/8" isn't numeric in modulus (%) Argument "4/8" isn't numeric in modulus (%) 0

      I find ->@* much less worrying than the above as the required prefix (->) is so much more explicit and visible. I'm not sure how I'd feel about the -> being optional in some cases (maybe it already is?).

      And the mentioned part of demerphq's argument that you linked to:

      my @things= $foo->@*;

      So, now, the $ no longer can be relied to refer to a "scalar", it might be a scalar, it might not.

      Complains about a guarantee that already isn't assured:

      my @things = $scalar->fetch_all_the_things();

      so I find that argument quite unconvincing.

      - tye        

        So, clearly, we need to drop the % (modulo) operator since we all know that % is supposed to be a sigil, and we mustn't blur the lines between sigils and operators. Same goes for & and *, by the way. ** looks like a glob named '*' so certainly must not be used as an operator. %= looks like a special hash.

        Actually, %= is a global hash. It is also the modulo-assignment operator.

        > say '%= = 0..9; $k = %=; $k %= %=;' Argument "4/8" isn't numeric in modulus (%) Argument "4/8" isn't numeric in modulus (%) 0

        I find ->@* much less worrying than the above as the required prefix (->) is so much more explicit and visible. I'm not sure how I'd feel about the -> being optional in some cases (maybe it already is?).

        Excellent example. Any variable =~ /^\Q$@%\E\W/ is, by convention, a special variable, and those that happen to be plain vanilla scalars, arrays or hashes currently, are special variable candidates as long as I know Perl books; and those should not be used as variables because:

        • no guarantee exists that those will not have a special meaning in a future release of perl
        • they look special and may be confused with operators and are confusing as part of their specialness

        So - no, we need not drop the modulo operator - me must not use "%=" as a hash! And this

        $\ = "\n"; *{'@*'} = sub { @{$_[0]} }; bless my $ref = [ qw(foo bar baz) ]; $method = '@*'; print for $ref->$method; __END__ foo bar baz

        while it works without use feature 'postderef', is plain weird - implementing the content of $method as a literal not less so.

        And the mentioned part of demerphq's argument that you linked to:

        my @things= $foo->@*; So, now, the $ no longer can be relied to refer to a "scalar", it +might be a scalar, it might not.
        Complains about a guarantee that already isn't assured:
        my @things = $scalar->fetch_all_the_things();
        so I find that argument quite unconvincing.

        Come on, $scalar->fetch_all_the_things(); is a method call, and objects are just references held in scalars, just like scalar, hash and array references. But your example brings up my next objection: $ref->@* looks like $ref being an object. Is it? should it be? In my humble opinion: no. There's already enough overhead in each perl run.
        Are we going in that direction, making everything into objects?

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'

      I am with demerphq on that: It breaks the original model of sigils completely.

      Except demerphq is mistaken. Perl5 sigils don't denote the type of result that will be returned.

      • @{ ... } evaluates to an array, a list or a scalar.
      • @{ ... }[1,2] evaluates to a list or a scalar.
      • %{ ... }[1,2] evaluates to a list or a scalar.
      • %{ ... } evaluates to a hash, a list or a scalar.
      • *{ ... } returns a scalar (glob).
      • *{ ... }{ARRAY} returns a scalar (reference).
      • &{ ... } can evaluate to a list or a scalar.
      • ${ ... }->() can evaluate to a list or a scalar.

      so

      • @ can evaluate to an array, a list or a scalar.
      • % can evaluate to an hash, a list or a scalar.
      • $ can evaluate to a list or a scalar.
      • & can evaluate to a list or a scalar.
      • * can evaluate to a glob or a reference.

      You already have to locate the end of the expression. Nothing's been broken.

        Except demerphq is mistaken. Perl5 sigils don't denote the type of result that will be returned.

        Of course they do, at least since perl4 patchlevel 36 (or 19 on Atari). The result of the evaluation of an identifier with its sigil may be coerced to something diferent depending on the context in which that evaluation is effective, but the evaluation of an identifier bare of any context depends on its sigil. If that were not the case, sigils would be pointless.

        perl -le'print map{pack c,($-++?1:13)+ord}split//,ESEL'
        %{ ... }[1,2] evaluates to a list or a scalar.

        That doesn't evaluate to anything, it is a syntax error.

        And the rest of the post is a straw man.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re^4: use feature 'postderef'; # Postfix Dereference Syntax is coming in 5.20 (*)
by BrowserUk (Patriarch) on Nov 26, 2013 at 16:12 UTC

    Ignoring the dubious nature of immediately flattening a returned array ref to an array, how is:

    my @got = ExactlyWhatThisReturns( $exactly, $what, $it, $is, $based, $on, )->@*;

    clearer than:

    my @got = @{ ExactlyWhatThisReturns( $exactly, $what, $it, $is, $based, $on ) };
    .

    Or this mess:

    my( $state, $zip ) = $user->GetAccount()->GetPriorOrder() ->GetShippingAddress()->@{ 'state', 'zip' };

    Clearer than this:

    my( $state, $zip ) = @{ $user->GetAccount()->GetPriorOrder()->GetShippingAddress() }{ 'state', 'zip' };

    But I guess these things are in the eye of the beholder.


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority".
    In the absence of evidence, opinion is indistinguishable from prejudice.
      my @got = @{ ExactlyWhatThisReturns( $exactly, $what, $it, $is, $based, $on ) };

      You've required an extra level of indentation. That adds complexity. In this case, with the made-up names, you compensated by removing an alternate level of indentation. But added complexity, even somewhat small, can add up. You can also squash that level of indentation with something like:

      my @got = @{ ExactlyWhatThisReturns( $exactly, $what, $it, $is, $based, $on, ) };

      but you've still added a layer of nesting. I believe a layer of nesting is fundamentally more complex than one more item on a chain of postfix operations.

      Also, in a case like:

      my @items = @{ $user->GetAccount()->GetPriorOrder()->GetItemCodes() };

      You have to mentally push a context that is moving in the opposite direction of the other operations. Again, a small cost in isolation, but just one more bit of complexity to add to the pile that might push something beyond a threshold for some readers and require a double take, and such disruptions in fluent reading of code can be jarring and significantly slow full comprehension.

      Reading the code your (well, my) mind goes, "Okay, I'm getting a list of items by dereferencing some... unknown thing, so we'll come back to that... Oh, I take the current user, get their account, get the prior order for that account, get the item codes for that order. Now, where was I? Oh yes, 4 operations ago I was supposed to remember a dereference. The '}' isn't followed by anything and um, oh yeah, we started with '@', so that means I'm turning a ref to an array into a simple list." Yeah, I find that way more complicated than what I'd have to think with ->@*.

      Alternately I can forgo scanning the code linearly and jump from the opening "@{" to try to find the matching "}" and then only push the simpler concept of "deref an array ref into a simple list". But I still have to mentally push the out-of-order operation. And visual jumping isn't free, especially if one of the functions involved takes complex arguments taking up half of a screen.

      I already mentioned one of my least favorite aspects of this:

      my( $state, $zip ) = @{ $user->GetAccount()->GetPriorOrder()->GetShippingAddress() }{ 'state', 'zip' };

      To understand just what kind of dereference is being requested, I have to line up two characters that are quite far apart in this code, the '@' near the end of the first line and the '{' near the beginning of the 3rd line.

      Also, consider that over the prior dozen years I've seen hundreds of people have significant difficulty when they've been doing $aoh->[$i]{$k} with no problem and then need to get something like the keys in one of the hashes and just draw a complete blank on how to do that. %{ $aoh->[$i] } is a significant departure in syntax.

      Heck, I had significant difficulty remembering the precise details of the various non-postfix (and less-often-used) ways of dereferencing until I realized that I could boil it down to references quick reference. I've linked to that node or seen others link to that node hundreds of times, almost always in reply to somebody having difficulty making the jump from postfix dereferencing to types of dereferencing that weren't possible via postfix syntax.

      Yeah, I've seen tons of evidence that it isn't just me who finds "SIGIL{ EXPR }SUBSCRIPTS" (where both the braces and the SUBSCRIPTS are optional) substantially more complex than postfix dereferencing.

      - tye        

        I should know better than to come back at you on this and just allow the visually obvious to win the day.

        (Especially as I don't really believe that you really believe half of what you've said in this thread.)

        But there are some things you said I just can't let pass.

        You've required an extra level of indentation. That adds complexity.

        No. It doesn't. Whitespace "adds complexity" is so obviously wrong. The "complexity" doesn't change one jot.

        The additional whitespace adds clarity. Better yet, it removes obfuscation.

        The reason we use indentation is to promote clarity; and improve readability. For the same reasons and goals (and achievements) as using paragraphs and sentences and bulleted lists in formal writing.

        Reading the code your (well, my) mind goes, "Okay, I'm getting a list of items by dereferencing some... unknown thing, so we'll come back to that... Oh, I take the current user, get their account, get the prior order for that account, get the item codes for that order. Now, where was I? Oh yes, 4 operations ago I was supposed to remember a dereference. The '}' isn't followed by anything and um, oh yeah, we started with '@', so that means I'm turning a ref to an array into a simple list." Yeah, I find that way more complicated than what I'd have to think with ->@*.

        I'd suggest that you're getting old, but i doubt your older than me, so that doesn't cut it.

        More likely, you are simple overstating the task. You are not a compiler. You do not need to process the entire statement to understand it.

        Its populating an array by dereferencing (a reference!) the return of a function call. (Full stop.)

        The function call returning that reference is .... (Full stop.)

        To understand just what kind of dereference is being requested, I have to line up two characters ...

        Again, no you don't. Again, you're overstating this.

        There's one bit -- made obvious by the "extra" level of indentation:

        $user->GetAccount()->GetPriorOrder()->GetShippingAddress()
        -- that chains through several method to finally arrive at what we want: a reference.

        Once we've got that reference, we dereference it and extract 2 fields from the hash. Clear as day.


        With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
        Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
        "Science is about questioning the status quo. Questioning authority".
        In the absence of evidence, opinion is indistinguishable from prejudice.
Re^4: use feature 'postderef'; # Postfix Dereference Syntax is coming in 5.20 (*)
by ikegami (Patriarch) on Nov 29, 2013 at 15:44 UTC

    But I'd be happy to have the '*' dropped so long as that doesn't introduce parsing difficulties

    I think that sentiment is universal. IIRC, the only reason * was used was because not using it would cause parsing difficulties.