Syntax understanding problem

Discussion in 'Perl Misc' started by Justin C, Dec 20, 2013.

  1. Justin C

    Justin C Guest

    I've just found something in code I wrote, but I don't
    understand it and don't know where I found it. I wrote it a long
    time ago. I have this line:

    ($discard = 0, next) if /^Relayed messages/;

    I was tweaking the program for a issue I had (that turns out to
    have been elsewhere), and changed the above to:

    $discard = 0 if /^Relayed messages/;

    At a later stage I had to revert to the original behaviour and
    put this:

    ($discard = 0 && next) if /^Relayed messages/;

    Which didn't do what I wanted!

    Where can I read about this behaviour of the comma? And what is
    that && doing in the last version, am I really saying ($discard
    = 0) and ($discard = next)?


    Justin.

    --
    Justin C, by the sea.
     
    Justin C, Dec 20, 2013
    #1
    1. Advertising

  2. you are using a list but instead of data, its items is executed code.
    More examples

    my
    @array;
    @array = ( print 12 , 1==1 ? 'foo' : 'boo' ) if 2==2;
    @array = qw/a b/ if 2==0;

    use Data::Dumper; print Dumper \@array
     
    George Mpouras, Dec 20, 2013
    #2
    1. Advertising

  3. Justin C <> wrote:
    >I've just found something in code I wrote, but I don't
    >understand it


    That's not surpising. You are (mis?)-using data structures as control
    flow elements. That is at the very least a rather questionable habit.

    >and don't know where I found it. I wrote it a long
    >time ago. I have this line:
    >
    >($discard = 0, next) if /^Relayed messages/;


    If the condition is true, then you are creating a temporary list that is
    never used. This list has 2 elements, first the value 0, and second the
    return value of next. As a side effect while calculating the first value
    it also sets $discard to 0. And of course 'next' never returns, so it
    does not really have a valid return value.

    >I was tweaking the program for a issue I had (that turns out to
    >have been elsewhere), and changed the above to:
    >
    >$discard = 0 if /^Relayed messages/;


    Well, this version obviously never jumps to the next incarnation of
    whatever enclosing loop you got.

    >At a later stage I had to revert to the original behaviour and
    >put this:
    >
    >($discard = 0 && next) if /^Relayed messages/;
    >
    >Which didn't do what I wanted!


    Not surprising that's something completely different. Here you got a
    list with only one element. And this element is calculated as the result
    of the assignment of the expression (0 && next) to $discard because &&
    has a higher precedence than the assignment.
    0 is logical 'false', therefore the && short-circuits and never
    evaluates the right side 'next' but instead returns 'false' immediately
    and that's what gets assigned to $discard. And then the code continues
    with the next statement.

    >Where can I read about this behaviour of the comma? And what is
    >that && doing in the last version, am I really saying ($discard
    >= 0) and ($discard = next)?


    No, why would you think so? You are saying
    ($discard = (0 && next)) if /^Relayed messages/;
    just as if you were writing
    ($foo = 4 + 9) if /^Relayed messages/;

    jue
     
    Jürgen Exner, Dec 20, 2013
    #3
  4. In article <>,
    Justin C <> wrote:
    > I've just found something in code I wrote, but I don't
    > understand it and don't know where I found it. I wrote it a long
    > time ago. I have this line:
    >
    > ($discard = 0, next) if /^Relayed messages/;


    This is just a cryptic perlish way of saying this:

    if (/^Relayed messages/) {
    $discard = 0;
    next;
    }

    It was just a way of dispensing with {} and making it a one-liner,
    which some people consider cool. (I'm not commenting on that opinion).

    > I was tweaking the program for a issue I had (that turns out to
    > have been elsewhere), and changed the above to:
    >
    > $discard = 0 if /^Relayed messages/;
    >
    > At a later stage I had to revert to the original behaviour and
    > put this:
    >
    > ($discard = 0 && next) if /^Relayed messages/;
    >
    > Which didn't do what I wanted!
    >
    > Where can I read about this behaviour of the comma? And what is
    > that && doing in the last version, am I really saying ($discard
    > = 0) and ($discard = next)?


    $ perldoc perlop

    Cheers
    Tony
    --
    Tony Mountifield
    Work: - http://www.softins.co.uk
    Play: - http://tony.mountifield.org
     
    Tony Mountifield, Dec 20, 2013
    #4
  5. Ben Morrow <> wrote:
    >instead this is 'the scalar comma operator', which is considered
    >reasonable to use to sequence side-effects.


    This I dare say is highly debatable. Just because it is possible to use
    data structures to control execution flow doesn't mean it is a good idea
    to do so. The OPs confusion is actually a good example why it is a
    pretty darn stupid idea.

    jue
     
    Jürgen Exner, Dec 20, 2013
    #5
  6. (Tony Mountifield) writes:
    > In article <>,
    > Justin C <> wrote:
    >> I've just found something in code I wrote, but I don't
    >> understand it and don't know where I found it. I wrote it a long
    >> time ago. I have this line:
    >>
    >> ($discard = 0, next) if /^Relayed messages/;

    >
    > This is just a cryptic perlish way of saying this:
    >
    > if (/^Relayed messages/) {
    > $discard = 0;
    > next;
    > }
    >
    > It was just a way of dispensing with {} and making it a one-liner,
    > which some people consider cool. (I'm not commenting on that opinion).


    It should be noted that this is your opinion about people who use
    certain syntactic constructs (they're irrational and do bad things
    because of that), camouflaged as asessement of the "deep, inner
    motivations of someone who 'does something you'd never do yourself'" and
    - completely unsurprisingly - you came to the conclusion that "they're
    probably mad" (since 'drunk' won't suffice here).

    $discard = 0, next if /^Relayed messages/;

    is another way of writing

    /^Related messages/ and $discard = 0, next;

    That's an expression using the short-ciruiting behaviour of the boolean
    operators for flow control, a possibility which has existed at least
    since C, except that Perl provides an alternate set of these operators
    whose precedence makes them more suitable for this use and an alternate
    syntax someone presumably considered to be clearer than using the
    operators. AFAIK, statement modifiers are indeed unique to Perl but
    different programming languages actually differ and decrying them as
    'cryptic' because they do make little sense ("You're all full of shit
    and everything someone who has learnt Math doesn't understand ought to be
    banned!" is an old Xah-Lee chestnut, pax hibiscus ...)
     
    Rainer Weikusat, Dec 20, 2013
    #6
  7. Rainer Weikusat <> wrote:
    >is another way of writing
    >
    >/^Related messages/ and $discard = 0, next;
    >
    >That's an expression using the short-ciruiting behaviour of the boolean
    >operators for flow control, [...]


    And exactly for this reason it is just as insane.

    Just do not mix code (control flow) and data (expressions).

    jue
     
    Jürgen Exner, Dec 20, 2013
    #7
  8. Ben Morrow <> wrote:
    >
    >Quoth J?Exner <>:
    >> Ben Morrow <> wrote:
    >> >instead this is 'the scalar comma operator', which is considered
    >> >reasonable to use to sequence side-effects.

    >>
    >> This I dare say is highly debatable. Just because it is possible to use
    >> data structures to control execution flow doesn't mean it is a good idea
    >> to do so. The OPs confusion is actually a good example why it is a
    >> pretty darn stupid idea.

    >
    >The code in question was not a 'data structure', it was the comma
    >operator in scalar (or, actually, void) context. The sole purpose of the


    The code in question is an expression. The purpose of an expression is
    to manipulate date, not to control execution flow.

    >behaviour of this operator is to allow this sort of sequencing of
    >side-effects within a statement, just like the equivalent operator in C.


    I never said that side-effects in statements that are used for control
    flow were a good idea in C, either.

    >Justin's confusion is more an example of why it is a bad idea to copy
    >code you don't entirely understand (sorry Justin) [...]


    Well, that's a given, isn't it?

    jue
     
    Jürgen Exner, Dec 20, 2013
    #8
  9. Justin C

    Tim McDaniel Guest

    In article <>,
    J_rgen Exner <> wrote:
    >The purpose of an expression is
    >to manipulate data, not to control execution flow.


    assert($args->{FLEX}, "Must say how to flex!");
    $count = $args->{COUNT} || 1;
    $source = $args->{ISUSER} ? $local : $global;
    open my $log, '>>', '/home/fred/debug' or die;

    --
    Tim McDaniel,
     
    Tim McDaniel, Dec 20, 2013
    #9
  10. Justin C

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >Apart from that, the scalar comma operator is explicitly intended for
    >control flow, just like 'and' and 'if' (and unlike '&&' and '?:').


    I see "and", "&&", and "?:" to be entirely equal: one thing is
    evaluated, and depending on the result, some other thing(s) may be
    evaluated, whatever the precedence (I consider requiting parentheses
    or no to be an inessential feature).

    As to whether you call it "control flow", it depend on your
    definition. I can think of several possible definitions:
    - the locus of execution moves outside the statement: next, last,
    return, ...
    - the locus of execution may skip or repeat the same statement, which
    is those plus the postfix statement modifiers
    - the flow of execution causes code to be skipped, but may remain in
    the same expression, being those plus: and or && || ?:
    I suppose one definition might be more useful than another depending
    on the discussion, so I'd define the term or avoid it.

    --
    Tim McDaniel,
     
    Tim McDaniel, Dec 21, 2013
    #10
  11. Justin C

    Justin C Guest

    On 2013-12-20, Ben Morrow <> wrote:
    >
    > Justin's confusion is more an example of why it is a bad idea to copy
    > code you don't entirely understand (sorry Justin) than of anything wrong
    > with the construction itself.


    No problem, Ben. I must have been under the impression that I
    understood it at the time I used it, but my understanding must
    have slipped since. I wouldn't just copy something I saw on the
    web. It was probably one of those "oh, that's clever" moments
    where I think "I must remember that, it'll save me..." and then
    promptly forget it.

    I'll probably replace it with Rainer's variation:

    /^Relayed message/ and $discard = 0, next;

    because this is clearer to me.

    The confusing part, for me, in perldoc perlop WRT the comma
    operator, is ``In scalar context it evaluates its left argument,
    throws that value away, then evaluates its right argument and
    returns that value''. I can understand the ``throws ... away''
    if I had:

    /^match/ and call_a_sub(foo), next;

    the return of call_a_sub would be discarded, but the assignment
    in my code isn't discarded.

    You know, by the time I get back to work, after Christmas, I
    may just do:

    if (/^Relayed message/) {
    $discard = 0;
    next;
    }

    Depends if it's still clear to me in the new year.

    Thank you all for the discussion.


    Justin.
     
    Justin C, Dec 22, 2013
    #11
  12. Justin C

    Tim McDaniel Guest

    In article <>,
    Justin C <> wrote:
    >/^Relayed message/ and $discard = 0, next;

    ....
    >The confusing part, for me, in perldoc perlop WRT the comma
    >operator, is ``In scalar context it evaluates its left argument,
    >throws that value away, then evaluates its right argument and
    >returns that value''. I can understand the ``throws ... away''
    >if I had:
    >
    >/^match/ and call_a_sub(foo), next;
    >
    >the return of call_a_sub would be discarded, but the assignment
    >in my code isn't discarded.


    It doesn't say "ignores the left argument completely"; in contrast, it
    says that it "evaluates" it. It says that it "throws that value
    away", "that value" being the return value of the evaluation. In

    >/^match/ and call_a_sub(foo), next;


    it still calls call_a_sub, and any global side effects from the sub
    remain (opening or closing files, setting global variables,
    whatever). The only thing discarded is the return value.

    An assignment statement returns a value:

    $ perl -e 'print ($x = 23, "\n")'
    23

    So in

    >/^Relayed message/ and $discard = 0, next;


    the assignment gets done and $discard is set to 0. It's just that the
    0 return value coming out of the assignment is discarded.

    --
    Tim McDaniel,
     
    Tim McDaniel, Dec 22, 2013
    #12
  13. (Tim McDaniel) writes:
    > In article <>,
    > Justin C <> wrote:
    >>/^Relayed message/ and $discard = 0, next;

    > ...
    >>The confusing part, for me, in perldoc perlop WRT the comma
    >>operator, is ``In scalar context it evaluates its left argument,
    >>throws that value away, then evaluates its right argument and
    >>returns that value''. I can understand the ``throws ... away''
    >>if I had:
    >>
    >>/^match/ and call_a_sub(foo), next;
    >>
    >>the return of call_a_sub would be discarded, but the assignment
    >>in my code isn't discarded.

    >
    > It doesn't say "ignores the left argument completely"; in contrast, it
    > says that it "evaluates" it. It says that it "throws that value
    > away", "that value" being the return value of the evaluation. In
    >
    >>/^match/ and call_a_sub(foo), next;

    >
    > it still calls call_a_sub, and any global side effects from the sub
    > remain (opening or closing files, setting global variables,
    > whatever). The only thing discarded is the return value.


    It might be easier to understand this when knowing the implementation:
    Internally, a list is represented as an OP_LIST (corresponding with
    pp_list) whose arguments are the elements of the list (Except when the
    list is an argument list for another list operator. In this case, the
    OP_LIST/ pp_list is elided). Implemented in Perl, the 'list operator'
    would look like this:

    sub list
    {
    return wantarray() ? @_ : $_[$#_];
    }

    which means the

    /^Relayed message/ and $discard = 0, next;

    is really something like this:

    /^Relayed messages/ and list($discard = 0, next); # [*]

    [*] Loop control is indeed allowed in 'argument lists', eg

    print("$_\n", ($_ & 1 and next) || '') for 1 .. 10;

    is a seriously bizarre way to print all even numbers from (1,10)
     
    Rainer Weikusat, Dec 22, 2013
    #13
  14. On 12/22/2013 6:48 AM, Tim McDaniel wrote:
    > In article <>,
    > Justin C <> wrote:
    >> /^Relayed message/ and $discard = 0, next;

    > ...
    >
    > it still calls call_a_sub, and any global side effects from the sub
    > remain (opening or closing files, setting global variables,
    > whatever). The only thing discarded is the return value.
    >
    > An assignment statement returns a value:
    >
    > $ perl -e 'print ($x = 23, "\n")'
    > 23
    >
    > So in
    >
    >> /^Relayed message/ and $discard = 0, next;

    >
    > the assignment gets done and $discard is set to 0. It's just that the
    > 0 return value coming out of the assignment is discarded.
    >


    Deparse (with or without brackets) may make it clearer:

    $ perl -MO=Deparse -e '/^Relayed message/ and $discard = 0, next;'
    -e syntax OK
    $discard = 0, next if /^Relayed message/;


    $ perl -MO=Deparse,-p -e'/^match/ and call_a_sub(foo), next'
    -e syntax OK
    (/^match/ and (call_a_sub('foo'), (next)));


    --
    Charles DeRykus
     
    Charles DeRykus, Dec 23, 2013
    #14
  15. Justin C

    Tim McDaniel Guest

    In article <>,
    Ben Morrow <> wrote:
    >
    >Quoth :
    >> >/^Relayed message/ and $discard = 0, next;

    >>
    >> the assignment gets done and $discard is set to 0. It's just that the
    >> 0 return value coming out of the assignment is discarded.

    >
    >Specifically, that = operator returns $discard, as a modifiable
    >lvalue.


    So far as I understand the rules,

    - a list assignment in a LIST environment returns the left-hand side
    as a modifiable lvalue

    - a list assignment in a SCALAR environment returns the number of
    elements in the RIGHT-hand side. Hence the goatse operator, =()=.

    - an assignment to a scalar in a LIST environment returns the
    left-hand side as a modifiable lvalue

    - an assignment to a scalar in a SCALAR environment returns 1, the
    number of "elements" on the right-hand-side?

    print (scalar (($a = 23) = 45), "\n");

    Do I have that right?

    --
    Tim McDaniel,
     
    Tim McDaniel, Dec 30, 2013
    #15
  16. Justin C

    Tim McDaniel Guest

    In article <l9s9cc$nte$>,
    Tim McDaniel <> wrote:
    >In article <>,
    >Ben Morrow <> wrote:
    >>
    >>Quoth :
    >>> >/^Relayed message/ and $discard = 0, next;
    >>>
    >>> the assignment gets done and $discard is set to 0. It's just that the
    >>> 0 return value coming out of the assignment is discarded.

    >>
    >>Specifically, that = operator returns $discard, as a modifiable
    >>lvalue.

    >
    >So far as I understand the rules,
    >
    >- a list assignment in a LIST environment returns the left-hand side
    > as a modifiable lvalue
    >
    >- a list assignment in a SCALAR environment returns the number of
    > elements in the RIGHT-hand side. Hence the goatse operator, =()=.
    >
    >- an assignment to a scalar in a LIST environment returns the
    > left-hand side as a modifiable lvalue
    >
    >- an assignment to a scalar in a SCALAR environment returns 1, the
    > number of "elements" on the right-hand-side?
    >
    > print (scalar (($a = 23) = 45), "\n");
    >
    >Do I have that right?


    Of course, as written, that would obviously simplify into two cases.
    But I don't understand what's going on.

    print (scalar (($a = 23)), "\n");
    print (scalar (($a = 23) = 45), "\n");

    prints

    23
    1

    .... unless the parentheses around the second assignment, which I added
    merely for precedence, make it considered a list assignment. But that
    would be so insanely stupid -- there would be no way to get a scalar
    assignment as in case 1, except maybe with an intervening sub call or
    somewhting.

    --
    Tim McDaniel,
     
    Tim McDaniel, Dec 30, 2013
    #16
  17. (Tim McDaniel) writes:

    [...]


    > print (scalar (($a = 23) = 45), "\n");
    >
    > prints
    >
    > 1
    >
    > ... unless the parentheses around the second assignment, which I added
    > merely for precedence, make it considered a list assignment.


    Ehh ... well ... ($a = 23) is obviously a list with a single elementy so

    ($a = 23) = 45

    is obviously a list assignment.
     
    Rainer Weikusat, Dec 30, 2013
    #17
  18. On 12/30/2013 9:20 AM, Tim McDaniel wrote:
    > In article <l9s9cc$nte$>,
    > Tim McDaniel <> wrote:
    >> In article <>,
    >> Ben Morrow <> wrote:
    >>>
    >>> Quoth :
    >>>>> /^Relayed message/ and $discard = 0, next;
    >>>>
    >>>> the assignment gets done and $discard is set to 0. It's just that the
    >>>> 0 return value coming out of the assignment is discarded.
    >>>

    >> ...


    > Of course, as written, that would obviously simplify into two cases.
    > But I don't understand what's going on.
    >
    > print (scalar (($a = 23)), "\n");
    > print (scalar (($a = 23) = 45), "\n");
    >
    > prints
    >
    > 23
    > 1
    >
    > ... unless the parentheses around the second assignment, which I added
    > merely for precedence, make it considered a list assignment. But that
    > would be so insanely stupid -- there would be no way to get a scalar
    > assignment as in case 1, except maybe with an intervening sub call or
    > somewhting.
    >


    The only quick ways to finesse the list context that occur to me:


    perl -E 'say scalar( (($a=23)=45)[-1] )'
    perl -E 'say scalar( do{($a=23)=45;$a} )'


    (can't think of any reason to do so however).

    --
    Charles DeRykus
     
    Charles DeRykus, Dec 31, 2013
    #18
  19. On 12/31/2013 3:42 PM, Ben Morrow wrote:
    >
    > Quoth Charles DeRykus <>:
    >> On 12/30/2013 9:20 AM, Tim McDaniel wrote:
    >>>
    >>> print (scalar (($a = 23) = 45), "\n");

    > [...]
    >>> ... unless the parentheses around the second assignment, which I added
    >>> merely for precedence, make it considered a list assignment. But that
    >>> would be so insanely stupid -- there would be no way to get a scalar
    >>> assignment as in case 1, except maybe with an intervening sub call or
    >>> somewhting.

    >>
    >> The only quick ways to finesse the list context that occur to me:
    >>
    >> perl -E 'say scalar( (($a=23)=45)[-1] )'
    >> perl -E 'say scalar( do{($a=23)=45;$a} )'

    >
    > I'm not sure what these are meant to do... in both cases the '= 45' is a
    > list assignment. If you want to perform a scalar context assignment to
    > the result of a scalar context assignment, I believe the simplest way is
    > like this:
    >
    > ${\($a = 23)} = 45;
    >
    > (Neither scalar() nor a do{} block can be assigned to, so although they
    > would be conceptually simpler they don't work.)
    >



    Did I skew off-tangent...? this was just a workaround to
    finesse the list context within case #2 and get the same results as
    case #1, ie, the complaint/challenge: "no way to get a scalar assignment
    as in case 1, except maybe with an intervening sub call or something"

    > print (scalar (($a = 23)), "\n"); # case 1
    > print (scalar (($a = 23) = 45), "\n"); # case 2
    > prints
    > 23
    > 1


    --
    Charles DeRykus
     
    Charles DeRykus, Jan 1, 2014
    #19
  20. On 12/31/2013 8:53 PM, Ben Morrow wrote:
    >
    > Quoth Charles DeRykus <>:
    >> On 12/31/2013 3:42 PM, Ben Morrow wrote:
    >>> Quoth Charles DeRykus <>:
    >>>> On 12/30/2013 9:20 AM, Tim McDaniel wrote:
    >>>>>
    >>>>> print (scalar (($a = 23) = 45), "\n");
    >>> [...]
    >>>>> ... unless the parentheses around the second assignment, which I added
    >>>>> merely for precedence, make it considered a list assignment. But that
    >>>>> would be so insanely stupid -- there would be no way to get a scalar
    >>>>> assignment as in case 1, except maybe with an intervening sub call or
    >>>>> somewhting.
    >>>>
    >>>> The only quick ways to finesse the list context that occur to me:
    >>>>
    >>>> perl -E 'say scalar( (($a=23)=45)[-1] )'
    >>>> perl -E 'say scalar( do{($a=23)=45;$a} )'
    >>>
    >>> I'm not sure what these are meant to do... in both cases the '= 45' is a
    >>> list assignment. If you want to perform a scalar context assignment to
    >>> the result of a scalar context assignment, I believe the simplest way is
    >>> like this:
    >>>
    >>> ${\($a = 23)} = 45;

    >>
    >> Did I skew off-tangent...? this was just a workaround to
    >> finesse the list context within case #2 and get the same results as
    >> case #1, ie, the complaint/challenge: "no way to get a scalar assignment
    >> as in case 1, except maybe with an intervening sub call or something"
    >>
    >> > print (scalar (($a = 23)), "\n"); # case 1
    >> > print (scalar (($a = 23) = 45), "\n"); # case 2
    >> > prints
    >> > 23
    >> > 1

    >
    > Someone is certainly confused here, but I'm not sure who it is...
    >
    > ...
    > I'm still not sure what you mean by 'finessing the list context'. Your
    > first example evaluates the '() = 45' list assignment in list context
    > (returning a list of one element containing $a as an lvalue), then
    > slices out the last element of that list, evaluating the slice in scalar
    > context (returning $a as an rvalue). The second achieves the same thing
    > by a different route, evaluating the list assignment in void context and
    > then returning $a as an rvalue directly from the do block. Neither case
    > returns a value that can be assigned to directly.
    >
    >


    Hm, I assumed there was already consensus that case #2 created a list
    context and case #1 didn't. The "finesses" were simple workarounds to
    force identical print output as I mentioned earlier. I suspect a more
    penetrating analysis was sought :)

    --
    Charles DeRykus
     
    Charles DeRykus, Jan 1, 2014
    #20
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Fran
    Replies:
    12
    Views:
    495
  2. joer3
    Replies:
    4
    Views:
    350
    James Kanze
    Jul 22, 2008
  3. buddy249
    Replies:
    1
    Views:
    573
    debayan_p
    Jun 23, 2009
  4. John Goche

    please help understanding syntax

    John Goche, Jan 7, 2012, in forum: Java
    Replies:
    5
    Views:
    350
    Roedy Green
    Jan 16, 2012
  5. scootiePuff
    Replies:
    0
    Views:
    170
    scootiePuff
    Apr 3, 2008
Loading...

Share This Page