perl-diddler has asked for the wisdom of the Perl Monks concerning the following question:

I was writing an expression to repeat spaces 'N' number of times but to prevent any cases where my indentation had grown "alot", I didn't want to indent any more than half-the screen with... thus, probably a common idea -- modulus the indent amount by the a limit -- I chose half the screen width.

Note, this question borders on discussing how many perl users can dance inside an array of size undef (and where would they be when doing so? Undef space?)... Seriously, though, back to the Q where we have an indent char/string the repeat operator 'x' and our count that needs to be arrived at via some arithmetic operations.

Wouldn't this tend toward some expression like:

' ' x $expr;
?

Under what circumstance would you want to evaluate some left-side of "$expr" and use it as an operand to the 'x' operator, and then multiply the result by the remaining right-side of the expression?

That's the main question. (um...why would someone care?)

It comes down to perl's precedence rules and a change that would allow perl to more often do something useful rather than than throwing an error and discarding what the user more than likely meant. Ex.

use warnings; use strict; my $col=10; my $maxcol=40; my $str = ' ' x $col%$maxcol;
The above throws an error that I can see no useful purpose for. The 'x' operator isn't commutative -- you have to have the string on the left, and you have to have the count on the right. So why not interpret the arithmetic portion first, then use that as the count?

Right now perl precedence rules for 'x' and % and the one below it, look like

left * / % x left + - .

Can people see the above precedence being useful? Note, any suggested change wouldn't be retroactively applied to older versions of perl (that almost always goes without saying, but just to make it explicit). So it would only change in P20 or P22 if it were to change, but why the above shouldn't be changed to prioritize arithmetic operators over string operators in an expression. I came up with:

1) left * / % 2) left + - 3) left x 4) left .

Note 2 - alternatively, and 'technically', one might think to keep rule 3 above rule 2, but in the same spirit of the above example, I don't see getting

Argument " " isn't numeric in addition (+) at -e line 2.
to be any more helpful than
Argument " " isn't numeric in modulus (%) at -e line 2.
To me, it looks like a prime situation for perl's precedence rules to change in a mostly backwards compatible way that would allow for cleaner code in the future.

I can think of at least 1 incompatibility: anyone who is maintaining a 15-20 y/o piece of code and feels they should be able to put "use <newest.version>;" at the top of their script, but complain that "'3'x 1+2". would no longer evaluate to '5', but instead to '333'. ;-/.

While the above might be useful in an obfuscated code contest, I'm not sure it really benefits the language's clarity or usefulness, whereas changing the precedence would allow for cleaner usage (as well as fewer errors).

By cleaner code, in this case, I'm referring to fewer required parantheses. In order to make the above, failing example 'work', you need parens around the arithmetic operators to have perl use that expression in a manner that would be useful with the string operator on the left. This change would give precedence to arithmetic operators over string operators when used in a mixed context, which might even have a[n almost immeasurable] benefit in execution speed.

Comments? Ideas? Any other similar ops besides "x" and "." that should be considered? Or do people find the current rules more intuitive and less error prone? If so, could you explain how? ;-)

Thanks for your insight!

Replies are listed 'Best First'.
Re: Precedence design question...'x' & arith
by davido (Cardinal) on Jul 05, 2013 at 02:23 UTC

    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

      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!

        "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
Re: Precedence design question...'x' & arith
by BrowserUk (Patriarch) on Jul 05, 2013 at 07:14 UTC

    I have a dim memory of someone saying that x has the precedence it has, so that you can write:

    print 'this' . ' ' x $spaces . 'that';

    Without the need for parens.

    If $spaces is variable, precalculate it:

    $spaces = $n * rand() + theNumberYouFirstThoughtOf(); print 'this' . ' ' x $spaces . 'that';

    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.
      print 'this' . ' ' x $spaces . 'that';
      This would function unchanged. Someone else made an erroneous statement about 'x' having higher precedence. It doesn't. It has the same as '*', '/', and '%'. I'm saying -- combine your integers first. So above -- without the need for parents, you can write your 2nd example in 1 statement:
      print 'this' . ' ' x $n * rand() + theNumberYouFirstThoughOf() . that' +;

      You can't do the above in 1 statement in perl, 'now', but you could if you bumped the **non-combining** string operations down 1 precendence level so you can evaluate the complete numeric expression, and use that as input to your 'x' operand which needs an integer on it's right side. Same holds true for '.' at same precedence as '+' and '-'.

      perl -we' print +2-2 . '*' . 2-2 .'='. -4+4-4+4 . '=' 0; ' #current perl: Argument "0*2" isn't numeric in subtraction (-) at -e line 2. Argument "-2=-4" isn't numeric in addition (+) at -e line 2. 2=0 # proposed would give the integer ops higher precedence and get them out of the way of the string-combining parts. Thus: perl -we' print +(2-2) . "*". (2-2) . "=" . (-4+4-4+4) . "=". 0 ."\n"; ' 0*0=0=0
      Thus showing the benefit and effect of proper precedence and evaluating the integer ops at higher precedence than the string ops.
      ∎ (Q.E.D.)?
      ;-)
        You can't do the above in 1 statement in perl, 'now', ...

        Of course you can:

        sub theNumberYouFirstThoughtOf{ 3 };; $n=1; print 'this' . ' ' x ( $n * rand() + theNumberYouFirstThoughtOf() ) . +'that';; this that

        I'm not arguing with your logic. But that's mostly because I cannot see the point in thinking about something that isn't going to change.


        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: Precedence design question...'x' & arith
by eyepopslikeamosquito (Archbishop) on Jul 06, 2013 at 08:16 UTC

    While I agree with your arguments that the current Perl 5 operator precedence could be improved, I don't feel it is appropriate to change operator precedence in a language as mature as Perl 5, with millions of lines of code in production use. That is, the (small) gain of your proposed change is not worth the considerable pain.

    A new language, like Perl 6, is another matter. And I see that the Perl 6 folks agree with you; that is, Perl 6 is already using your proposed operator precedence for its Replication (x and xx) and Concatenation ~ operators.

    By the way, notice that the current Perl 5 string multiply precedence is the same as Ruby and Python because they both use * as the string multiply operator. Ditto for string concatenation because Ruby and Python both use the + operator for that.

    Though string multiply may be rarely used in general Perl coding, it is heavily used in golf ... so your proposed precedence change would certainly be welcomed by golfers. :) To illustrate, in The golf course looks great, my swing feels good, I like my chances (Part VI), a very rare example of Python out-golfing Perl and Ruby was given:

    $"x(318%$_/9) Perl " "*(318%i/9) Ruby 318%i/9*" " Python
    Python was shortest here because the string multiply operator is commutative in Python (only), allowing the parentheses to be removed. That said, the most common use of string multiply in golf is with a boolean expression, for example:
    "Zaphod Beeblebrox"x($n!=42)
    and your proposed precedence change wouldn't help there.

      Perl6 is compatible with perl5?

      What I am suggesting is.

      This is a statement that so many people don't get -- Programs cannot be *relying* on getting an error for wrong usage in a production program, as errors wouldn't deliberately be in the end program. I'm taking a case that people can't use and suggesting that a bit of extra clarity in precedence would create a more useful language without taking away usable features or causing incompatible change.

      Nothing would help in your last example as it isn't intended to mean anything.

      And if you altered the precedence in the manner I proposed, the golf course example would be:

      ' 'x318%i/9
      as the integer ops are done first.
Re: Precedence design question...'x' & arith
by kcott (Archbishop) on Jul 05, 2013 at 04:29 UTC

    G'day perl-diddler,

    To be honest, I got the impression that you made a coding error

    $ perl -MO=Deparse,-p -e 'my $str = " " x $col%$maxcol;' (my $str = ((' ' x $col) % $maxcol)); -e syntax OK

    and instead of simply fixing it with the addition of a pair of parentheses

    $ perl -MO=Deparse,-p -e 'my $str = " " x ($col%$maxcol);' (my $str = (' ' x ($col % $maxcol))); -e syntax OK

    you decided that Perl should change to accomodate you.

    If you simply want a maximum amount of indentation, your logic (regardless of syntax) is wrong. When you see your output starting to zigzag across the screen, will you change your code to

    $ perl -MO=Deparse,-p -e 'my $str = " " x $col > $maxcol ? $maxcol : $ +col;' (my $str = (((' ' x $col) > $maxcol) ? $maxcol : $col)); -e syntax OK

    instead of

    $ perl -MO=Deparse,-p -e 'my $str = " " x ($col > $maxcol ? $maxcol : +$col);' (my $str = (' ' x (($col > $maxcol) ? $maxcol : $col))); -e syntax OK

    and then want the precedence of the ternary operator to change as well.

    Now, let's say your indentation was based on tabs of four spaces and your check also needed to take a margin into consideration. This code would no longer work as expected under your new precedence rules:

    $ perl -MO=Deparse,-p -e 'length " " x $expr + $margin' length(((' ' x $expr) + $margin)); -e syntax OK
    "The 'x' operator isn't commutative"

    So what? The '/' and '%' operators aren't commutative either: do you want to change their precedence as well based on commutativity?

    "So it would only change in P20 or P22 if it were to change, ..."

    By that, I assume you mean version 5.20 or 5.22. The 'x' operator has been around, with the same precedence, since at least Perl 4 (it's in my first edition Programming perl) — so, that's at least 22 years (see perlhist) of code that could potentially just break for anyone upgrading perl.

    "To me, it looks like a prime situation for perl's precedence rules to change in a mostly backwards compatible way ..."

    There is nothing in your post that suggests backwards compatibility. Perhaps you also want:

    use feature 'diddler_precedence';

    In closing, I see no merit whatsoever in what you're proposing. Just add the parentheses to your broken code and move on with your life.

    -- Ken

      To be honest, I got the impression that you made a coding error
      Where did you get that impression? Did I ask why it didn't work? Could you explain what could possibly have given you that impression in anything I wrote?

      I get the impression that you are used to deciding what people want to do (or did do) and going off on a tangent. Example:

      If you simply want a maximum amount of indentation, your logic (regardless of syntax) is wrong. When you see your output starting to zigzag across the screen, will you change your code to
      This is a 2nd example in the same posting of you making assumptions about what I wanted and having no basis for doing so. You then go on to soapbox about how I should have done it. You didn't answer the original question at all but seem to be wanting to direct it onto something else entirely.

      Tell me, when you write text on a page, when you get to the right-hand margin, do you then write one letter per column going down, or do you zig-zag your writing back and forth?

      Most writers discover that when they push all their writing into one column, not only does it become unreadable, but they would lose any future changes in indentation. How would you propose to communicate the indent level increasing or decreasing after you've hit say, column 40 out of 80? Your suggested correction is based on your trying to fit my problem into your own problem. I don't want

      simply want a maximum amount of indentation,
      I want something that shows me when indentation has increased and decreased.

      Then you go off into another problem about tabs and how my algorithm won't work for that? Irrelevant to my problem space -- it's debug output.

      Which brings me back to the original problem where you think I made some coding mistake and want perl to change to fix it. Please explain why you think the current syntax is superior to what I suggest.

      You seem to think I wrote asking for your specious advice based on my lying about the initial assumptions. That you have a propensity such doesn't mean everyone does. Some of us are honest to a fault.

      What I want is for you to simplify my expression down to one single expression that needs no parentheses. I maintain that they need for parentheses in this simple expression are inherently unnecessary, and that perl requires them seems inefficient. It is an example of the lack-of-expressiveness in the language -- a lack of conciseness. Rather than doing something *useful*, it has to generate an error for a case that shouldn't be an error in the first place.

Re: Precedence design question...'x' & arith
by hdb (Monsignor) on Jul 05, 2013 at 07:05 UTC

    I have spoken out against such changes in the past (Re: Thoughts on replacing -> with .) because I think that the benefits are overestimated relative to the costs.

    Here, only the wizards will be sure they know what they are doing, when they omit the parentheses. And the wizards will know that the x-operator has higher precedence. Changing Perl to the more intuitive way (I admit it would be) will break older code and will be very difficult to spot.

    I also think that less parentheses is not automatically cleaner code. Especially, when you have to remember rarely used and recently changed precedence rules.

    And lastly, your initial post has already more than 3000 characters, not counting your follow ups, which makes more than 1500 pairs of parentheses you could have typed in your code... ;)

      The example you give would be an incompatible change.

      Please understand, I'm suggesting a case where due to insufficient precision in precedence, the expression " " x 3*2, has no meaning in perl and yields an error.

      Syntactically, it is valid, but perl's semantics turn that statement into a semantic "void"... that does nothing for perl or perl authors.

      I'm asking to be able to use perl's "voids" (things that don't work by virtue of language semantics) and make them both useful, and, in the process, increase the power of perl as an expressive language. I'm not asking that anything other than obfuscation fodder be given up.

      If your preference is for perl to be obfuscated vs. concise and powerful, you are hurting perl's future. Languages are living things -- unless they are dead languages -- which means no one uses them.

      I asked for any useful case the current semantics are used for that would be harmed by my changes -- so far no one has come up with 1 example -- just F.U.D. (not to mention accusations of outright lying, 'Eh mate?'). While this is not an overwhelmingly positive outcome, it does seem to be proof that no one can come up with any useful examples in their own code that would be hurt by this change -- likely because using this syntax would currently through an error. Thus my assertion that it was backwards compatible, as it seems no one can come up with any real-life examples where they use or rely on current behavior.

      @superdoc -- I have to write extra long to just ***try*** to clearly get my meaning across. I have enough problems with people going off on tangents because of things I didn't imply or say -- though 2ndly with not saying things clearly enough. *sigh*...

      *concisely challenged* && still working on it!

Re: Precedence design question...'x' & arith
by parv (Parson) on Jul 05, 2013 at 02:30 UTC
    I personally would prefer string ops to have a lower precedent than arithmetic ones, regardless of any code breakage. Then again, one can always specify the order as one likes (e.g. '-' x ( 0 % 2 )).