in reply to Precedence design question...'x' & arith

Just for my own edification, are there any examples of Perl operators that changed precedence in mainstream Perl releases? Let's not consider the addition of new operators to be a "change of precedence", for this discussion.

I ask, because it strikes me as one of those things that would be a really bad idea. It's easy to look at //= and know, "Oh, I better be using Perl 5.10 or newer." But it's really hard to look at an operator and have to worry that code that uses it might break due to precedence changes between Perl versions.

Oh wait! We could use another pragma: "use funky_precedence;", and then we have to skim through code to determine if it's using new or old precedence semantics.

This is a feature idea that, once again, adds complexity, a huge potential for new bugs in existing code as well as in the Perl interpreter, without making anything that was previously hard or impossible now easy or possible.


Dave

Replies are listed 'Best First'.
Re^2: Precedence design question...'x' & arith
by perl-diddler (Chaplain) on Jul 05, 2013 at 05:47 UTC
    I ask, because it strikes me as one of those things that would be a really bad idea. It's easy to look at //= and know, "Oh, I better be using Perl 5.10 or newer.

    And I was just thinking yesterday about how perl made // and operator while in other languages it was the lead-in to a comment and how perl has no syntactic multi-line comment blocks.

    But if you saw:

    ' ' x $a * $b;
    You would have to know that for that to work, you'd have to be in perl 5.20 or newer, as it throws an error if you try to multiple a string times an integer.

    It's not like you have a choice. You say :

    it's really hard to look at an operator and have to worry that code that uses it might break due to precedence changes between Perl versions.
    But the fact is you wouldn't. If you had an expression like the above, it would be broken and not work pre-pV20 (or whatever). If you are using such a construct in your current perl -- my question was how are you doing it? Could you give some examples of how you use the current behavior to produce useful code?

      Making a string, the space in your example, be the result of (numerical) multiplication seems like nonsense to me. If my code said

      my $foo = 'bar'; my $aaa = 3; # to avoid sort's special vars, $a & $b my $bbb = 2; my $result = $foo * ($aaa *$bbb); say "\$result is: $result"; =head Argument "bar" isn't numeric in multiplication (*) at D:\_wo\1042598.p +l line 11. $result is: 0 =cut

      and I didn't get an anguished squawk from the compiler, I would be horrified. In fact, I'm semi-horified that this is only a warning, rather than a fatal error.


      If you didn't program your executable by toggling in binary, it wasn't really programming!

        Absolutely. I agree! And that is the point.

        The integer operators like '*', '%', and "/" have no place being applied to a string. They only apply to other numbers. Thus I proposed that those operators have higher precedence so that all the integer ops would go away and all we would be left with was the "x' (the string repeat operator).

        i.e

        'a' x 3 => 'aaa' 'a' x 3*2 => 'aaa' * 2 ==> error You can never combine the math operators with strings (unless the string happens to be a number) ex: '2' x 3*2 = 222*2 => 444, but that's a pretty unclear way to multiply +222 by 2.
        That is why, I suggested the math ops be gotten out of the way first.

        If 'x' was commutative like '*', then we could say

        [sic] 3*2 x ' '
        And get our answer, But the 'x' is not commutative -- you can't switch the order of the operands. It always uses the left side as the string to be acted upon and always uses the right side as the count. Thus it only makes sense to reduce any numeric expression on the right side before applying it to the string on the left.

        Unfortunately, perl put 'x' in the same class as '*' and uses left to right evaluation. Since you are operating on 2 different data types in the same expression, it is common to perform evaluation on the same typed operands first, then apply that to the other operand.

        Example -- in 'C', the string operations are always done separately from the integer ops by virtue of the string ops being separate functions. It would be a natural evolution from C's syntax (which perl's is said to derive from), to do the integer ops first then pass result to the C function:

        a=2*3;str=' ';while (a--) strcat(str,str);
        You could not easily have a bad situation like ' ' x 2 * 3 in 'C', because the integer count construction is always done first, and the result passed to the string op.
        "In fact, I'm semi-horrified that this is only a warning, rather than a fatal error"
        Me too!... I make all warnings fatal w/trackback. You can just ""use warnings 'all=>FATAL'; I got a bit more involved and wrote an 'ExceptionHandler' that handles errors, warnings and signals.
        use ExceptionHandler;
        # then I can:
        Register_Traceback; #default is to register traceback for #SIGDIE & SIGWARN
        and setup handlers to dump a trace-back and quit:
        Regsister_Traceback('QUIT') #(control-\) So if I get stuck in an infinite loop somewhere, pressing ctl-\ instead of ctl-c will give me a traceback before exiting. Optio +nally the trackback registration can take a pointer to your own routine to call. Based on the return value of your own coded handler, Perl will then take an action based on the setup: <code> # sig, callback|disposition # disposition = sign-bit=exit immediate # = (0) = exit # = 1-7 if (devel){stack trace} + ignore "X" times + exit # = 0x10 = message/nomessage # = 0x20 = 0=count in bottom nibble, 1=noexit # = callback and status returns above val for further # = processing
        So my warning handler could ignore some warnings, and return 0x21 for count in bottom nibble 1=noexit for those warnings, but die on others.

        What some people don't get about my code -- is that there is that debug and error handling make up to 50% of some of my programs. I'm far more likely to make an error than not, and my progs are sufficiently complex they need smart self-diagnostics or I'm screwed. Just like another answer writing made some crazy assumptions about my *debug* code's indentation routine. I didn't go into the fact that it was in a debug routine because I didn't think it was pertinent to a discussion of string v. numeric operand precedence.

        A good article to read about language power and design which fairly well points out reasoning for removing the parens from my original example and strengthening perl's expressiveness to increase code clarity and power, can be read at: http://hillside.net/plop/2010/papers/gunther-2.pdf where he talks about domain specific additions to a language such as ruby or python. He left out perl, but he hints at a reason:

        However, analyzing the relevant literature 33, 44, 27, 49, 11, 9 reveals that there are several design principles of DSLs, such as abstraction to make domain concepts explicit programming language constructs, absorption to integrate implicit and common domain knowledge in the DSL, or compression to yield a concise domain notation.
        Perl suffers a lack of inherent abstraction and absorption allowing integration of implicit and common knowledge. -- Example:
        ' ' x 3*2
        Anyone who knows perl fairly well, knows that the above fails to abstract the concept of allowing 6 repeats of space. If it produced a valid result that was different (Suppose strings were automatically treated as base 64 -- then it might make sense to multiple a string by a numeric operand. But such is not the case. As it is, a logical design would require the integer operands to be evaluated first because not doing so leaves a semantic void in the language. Rather than being an expression with meaning, the syntax is wasted due to ill-prioritized precedence rules.

        I'm saying those can be fixed without harming backwards compat, since they don't express valid constructs in earlier versions of the language.

        make sense?

      "You would have to know that for that to work, you'd have to be in perl 5.20 or newer, as it throws an error if you try to multiple a string times an integer."

      It only complains if you have numeric warnings switched on (which they are not by default) - and that's only a warning, not an exception, unless you enable fatal warnings.

      package Cow { use Moo; has name => (is => 'lazy', default => sub { 'Mooington' }) } say Cow->new->name