in reply to 5.10 smart match behaviour

A list (which is what your constant sub returns) isn't an array.

Update: Perhaps this will help. Remember what a LIST in scalar context evaluates as.

perl5.10.0 -E'BEGIN{ sub X () { say "wantarray: ", defined wantarray ? + (wantarray eq "" ? "empty" : wantarray) : "undef"; qw(a b c) } } say + "ok" if "a" ~~ X'

The cake is a lie.
The cake is a lie.
The cake is a lie.

Replies are listed 'Best First'.
Re^2: 5.10 smart match behaviour
by ikegami (Patriarch) on Jun 10, 2008 at 13:35 UTC

    Did you just say "list in scalar context"? There's no such thing! His sub is *not* returning a list.

    Maybe you meant "the comma operator in scalar context", but that would presuppose that functions built by constant use the comma operator.

    In fact, it appears that the comma operator is *not* used. Quote the docs (emphasis in original),

    Note that constants with more than one value do not return their last value in scalar context as one might expect. They currently return the number of values, but this may change in the future. Do not use constants with multiple values in scalar context.

    That means that X (as built by constant) returns 3 in scalar context for the current version of constant, and that you shouldn't count on that always being the case.

      Oop, quite right.

      My constant stand-ins were using qw// directly which was behaving comma-like in imposed scalar context rather than passing through another layer (as happens with constant where the args get packaged up into an array and then turned into sub () { @list } which instead behaves like one would expect an array evaluated in scalar context imposed by the caller). More precise would have been "a sub whose return value is a list generated via qw// called in a scalar context", but that's not what he had due to how constant works now so he instead had "a sub whose return value is an array called in a scalar context".

      In either case they're both a single scalar value neither of which ('c' nor 3) match.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      ikegami++, thanks for pointing out very clearly what the problem was, in terms of contexts.
      But as almut++ also pointed out, i'm still thinking it's more a matter of non-DWIM behaviour.
      You'd say, well, we've got warnings for that. :)

      One of the problems is, if these are equivalent (because of the context imposed on X):
      perl -Mstrict -wE'use constant X => qw(a b c); say "ok" if "a" ~~ X'
      and
      perl -Mstrict -wE'use constant X => qw(a b c); say "ok" if "a" == X'
      that smart match breaks the warning:
      Argument "a" isn't numeric in numeric eq (==) at -e line 1.

      We could at least work towards a fix for this, maybe ?

      -- 
      
      perl -MLWP::Simple -e'print$_[rand(split(q|%%\n|, get(q=http://cpan.org/misc/japh=)))]'
Re^2: 5.10 smart match behaviour
by zgrim (Friar) on Jun 10, 2008 at 12:45 UTC
    I didn't say the GV was an AV, the sub was an array, or anything internals in particular.
    I only expected smart match to be consistent (in a DWIM fashion).

    -- 
    
    perl -MLWP::Simple -e'print$_[rand(split(q|%%\n|, get(q=http://cpan.org/misc/japh=)))]'

      I think you're missing my point. It does seem to consistently evaluate the arguments on both sides in a SCALAR context if it's an EXPR and not an actual variable name (similar to how (say) keys requires something literally begining with a % to work upon). That means that your constant sub is being evaluated in scalar context returning the final element of the LIST, just as everywhere else you have a true LIST in scalar context.

      1 #!/usr/local/bin/perl5.10.0 2 use feature ":5.10"; 3 4 BEGIN { 5 sub ctx () { 6 my @caller = caller(1); 7 say "$caller[3]:$caller[2] wantarray: ", 8 defined $caller[5] 9 ? ( $caller[5] ? "yes" : "no" ) 10 : "undef"; 11 } 12 13 sub ret_scalar () { ctx; "a" } 14 sub ret_list () { ctx; @{[ qw/a b c/ ]} } 15 } 16 17 ret_scalar; 18 my $a = ret_scalar; 19 my @a = ret_list; 20 21 my $list_in_scalar = ret_list; 22 say "list in scalar: ", $list_in_scalar; 23 24 my @scalar_in_list = ret_scalar; 25 say "scalar in list: ", join( ", ", @scalar_in_list ); 26 27 say "match" if ret_scalar ~~ ret_list; 28 say "match" if ret_list ~~ ret_scalar; 29 say "match" if ret_scalar ~~ [ ret_list ]; 30 31 __END__ main::ret_scalar:17 wantarray: undef main::ret_scalar:18 wantarray: no main::ret_list:19 wantarray: yes main::ret_list:21 wantarray: no list in scalar: 3 main::ret_scalar:24 wantarray: yes scalar in list: a main::ret_scalar:27 wantarray: no main::ret_list:27 wantarray: no main::ret_list:28 wantarray: no main::ret_scalar:28 wantarray: no main::ret_scalar:29 wantarray: no main::ret_list:29 wantarray: yes match

      I will grant you that I couldn't find documentation in my quick once over explicitly documenting that EXPRs would be evaluated in scalar context. In any case the quick fix is to either change your constant sub to return an arrayref or wrap the call to the constant sub in an anonymous arrayref constructor.

      Update: Duur, as is pointed out below it's a binary operator so that's probably why it's not explicitly spelled out.

      Update the second: Tweaked ret_list to behave more like the sub generated by the OP's constant call than my initial version's sub ret_list () { ctx; qw/a b c/ } did; still doesn't match because of the scalar context imposed but the exact value that doesn't match is 3 rather than 'c'.

      The cake is a lie.
      The cake is a lie.
      The cake is a lie.

      It's impossible.

      I started writing a bunch of "if you do X, then problem Y surfaces", but the problem always boiled down to the need to differentiate between a scalar and a one item list. Perl is fundamentally unable to do that.

      Without the ability to differentiate between a scalar and a one item list, almost if not all matches become indistinguishable from

      @array ~~ @array

      While that's a useful test, so are all the test that would be lost.