Beefy Boxes and Bandwidth Generously Provided by pair Networks
The stupid question is the question not asked
 
PerlMonks  

~~ and list literal

by Anonymous Monk
on Oct 25, 2012 at 10:33 UTC ( [id://1000809]=perlquestion: print w/replies, xml ) Need Help??

Anonymous Monk has asked for the wisdom of the Perl Monks concerning the following question:

Why does "x" ~~ ("x", "y", "z") not work? Is it because ~~ forces a scalar context or something? Aside from changing the code to "x" ~~ ["x", "y", "z"], is there another way?

Replies are listed 'Best First'.
Re: ~~ and list literal
by 2teez (Vicar) on Oct 25, 2012 at 12:07 UTC

    1. Please check perlop under the subheading
      Smartmatch Operator
      ..It is also unique in that all other Perl operators impose a context (usually string or numeric context) on their operands, autoconverting those operands to those imposed contexts. In contrast, smartmatch infers contexts from the actual types of its operands and uses that type information to select a suitable comparison mechanism...
    2. Moreover, using this
      print( "x" ~~ ("x", "y", "z") );
      with use warnings in your script turn on, it would shout"Useless use of a constant (x),(y) in void context". Which shows you are inferring a void context using smartmatch like so.

    If you tell me, I'll forget.
    If you show me, I'll remember.
    if you involve me, I'll understand.
    --- Author unknown to me

      TIL that parentheses don't imply a list context. Also these don't:

      "x" ~~ qw(x y z) "x" ~~ sort(x y z)

      I find that only this do: "x" ~~ @{["x", "y", "z"]}

      Any other which I missed?

        TIL that parentheses don't imply a list context

        Ofcourse, I never said parentheses imply a list context, it's the comma operator that does.
        But, what I did say/wrote is that the smartmatch ..infers contexts from the actual types of its operands and uses that type information to select a suitable comparison mechanism...

        Any other which I missed?
        Please, check perlop for detailed information

        If you tell me, I'll forget.
        If you show me, I'll remember.
        if you involve me, I'll understand.
        --- Author unknown to me
Re: ~~ and list literal
by Anonymous Monk on Oct 25, 2012 at 10:39 UTC

    What are you trying/hoping to do?

    $ perl -MO=Deparse,-p - print( "x" ~~ ("x", "y", "z") ); ^Z print(('x' ~~ ('???', '???', 'z'))); - syntax OK
    ??? means value is discarded, meaning it is same as 'x' ~~ 'z'

    Aside from changing the code to  "x" ~~ ["x", "y", "z"], is there another way?

    Yeah, without ~~

      I was trying to find an element in a list, like in an array with "x" ~~ @ary (which works).
Re: ~~ and list literal
by ikegami (Patriarch) on Oct 25, 2012 at 22:21 UTC

    First, why what you have there doesn't work.

    The arguments of ~~ are necessarily evaluated in scalar context. ($x ~~ @a is just a shorthand for $x ~~ \@a.) That means that ~~ ("x", "y", "z") is equivalent to ~~ "z", as you were advised by warnings.

    Secondly, getting the behaviour you do want.

    Well, you want the SCALAR ~~ ARRAY behaviour, so you'll need an reference to an array, so you'll need an array. "x" ~~ ["x", "y", "z"] and "x" ~~ any("x", "y", "z") are the most concise means of achieving that with ~~. (any provided by Smart::Match).

    If you don't mind moving away from ~~, you could also use grep "x" eq $_, ("x", "y", "z").

      Hi ikegami,

      Thanks, I think I get it now why it doesn't work. Pity though because my eyes want "x" ~~ ("x", "y", "z") to work, it looks intuitive.

      About your suggestions: Smart::Match isn't core and it incurs some runtime penalty. And I believe grep doesn't shortcut?

        Funny, I ran into the exact same problem like ten minutes ago and decided to feed the error message to the Monastery which turned up this thread :) I was trying to make some older code visually simpler now that it requires 5.10.1+ anyway.

        Yeah, that listref is not the most intuitive construction although visually the square brackets work OK for me; round ones would look redundant. What I used before was List::MoreUtils, which while non-core is fairly ubiquitous and has "any" that does shortcut. Though with lists of a size that you want to specify as literals in the source it probably makes zero difference.

      Follow-up question:

      Why does "x" ~~ "a", "b", "c" always give 1? Running through Deparse gives: 'x' ~~ 'a', '???', 'c'. What is going on here?

      And why does "x" ~~ sub { "a", "b", "c" } also give 1? Smart match is giving me a headache...

        Why does "x" ~~ "a", "b", "c" always give 1?

        It doesn't; it evaluates to "c".

        "," is a very low precedence operator. "x" ~~ "a", "b", "c" means ("x" ~~ "a"), "b", "c", which evaluates to "c" in scalar context.

        And why does "x" ~~ sub { "a", "b", "c" } also give 1?

        It doesn't; it evaluates to "c".

        "x" ~~ sub { "a", "b", "c" } is the same as scalar( sub { "a", "b", "c" }->($x) ). Since  "a", "b", "c" evaluates to "c" in scalar context, that is what is returned.

        With the ~~ operator having much higher precedence than the comma, this is parsed as a comma-list of a smart-match whose result doesn't matter, more stuff that doesn't matter at all, and "c" which is true.

        The second one would pass "x" to the sub which again evaluates a comma-list and throws away everything (including the argument) but "c" which gets returned and is true.

        ...

        Because of precedence/binding

        Consider

        $ perl -le " $f = 1,2,3 ; print $f" 1 $ perl -MO=Deparse -le " $f = 1,2,3 ; print $f" BEGIN { $/ = "\n"; $\ = "\n"; } $f = 1, '???', '???'; print $f; -e syntax OK

        Compare it to

        $ perl -le " $f = ( 1,2,3 ); print $f" 3 $ perl -MO=Deparse -le " $f = ( 1,2,3 ) ; print $f" BEGIN { $/ = "\n"; $\ = "\n"; } $f = ('???', '???', 3); print $f; -e syntax OK

        Since smart is binary (like = in the above example), it works on two scalars, left-scalar operator right-scalar

        If you have no parentheses, the first scalar is taken, the closest, because assignment operator (=) has higher precedence than comma opeartor (it binds tighter).

        If you add parenthesis, then you have the fabled List in Scalar Context, then the comma operator return the last right item (rightest most)

        See Tutorials: Precedence for Idiots

        Since you're confused about precedence you're probably also confused about context, so see Tutorials: Context in Perl: Context tutorial, "List" Is a Four-Letter Word, Easy Reference for Contexts

        Smart match is giving me a headache...

        Stop using it :) worked for me :) Smart-match

Re: ~~ and list literal
by LanX (Saint) on Oct 25, 2012 at 13:52 UTC
      "List literal" is mentioned like a dozen times in the Llama book. I think that means it exists :)

Log In?
Username:
Password:

What's my password?
Create A New User
Domain Nodelet?
Node Status?
node history
Node Type: perlquestion [id://1000809]
Approved by Corion
help
Chatterbox?
and the web crawler heard nothing...

How do I use this?Last hourOther CB clients
Other Users?
Others having a coffee break in the Monastery: (3)
As of 2024-04-19 17:49 GMT
Sections?
Information?
Find Nodes?
Leftovers?
    Voting Booth?

    No recent polls found