in reply to Re^21: Why is the execution order of subexpressions undefined?
in thread Why is the execution order of subexpressions undefined?

But that's the whole reason evaluation order doesn't matter in Erlang.

As I already pointed to the other anonymonk, I did not mention Erlang in that context. Only as a (preferable) altenative to Haskell, especially with regard to it's treatment of concurrency, so stop stating the obvious.

And lack of that feature in Perl is exaclty the cause of all your problems.

I don't have any problems. I never did. Read the title of the thread, I simply asked why.

And so far, noone has offered a single good reason why EO should not be defined in Perl, nor countered my assertion that Perl does not benefit from it's being undefined in terms of efficiency, which is the only reason so far offered.


Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
Lingua non convalesco, consenesco et abolesco.
Rule 1 has a caveat! -- Who broke the cabal?
  • Comment on Re^22: Why is the execution order of subexpressions undefined?

Replies are listed 'Best First'.
Re^23: Why is the execution order of subexpressions undefined?
by Tanktalus (Canon) on Apr 15, 2005 at 03:52 UTC

    I would disagree. The ability to parallelise in perl6 is an awesome reason to leave EO undefined. Defining EO necessarily serialises statements, which would prevent future perl interpreters from automatically threading inside single, complex statements, and thus gaining huge amounts of efficiency on multi-processor systems.

    This is more than a good reason, and has been offered.

    Perl, as it is today, probably does not benefit from undefined EO. Perl as it may be in the future, would be hamstrung by an attempt today to define EO, as we would not be able to offer backwards compatability. True, perl6 does not offer backwards compatability with perl5. But who says perl 5.12 won't finally have a working, stable threading system built-in, and be able to use it?

      Would you agree that Perl could only implicitly parallelise functions, methods or tied variables if they appear in the same statement?

      If the programmer places them on separate lines, he is implying serialisation.

      Let's get abstract. In the following code, func1() and func2() return results obtained from slow external resources that lend themselves to automated threading. Think overlapped IO for example.

      For the sake of contrivance, and as we are being abstract, we'll assume that func2() requires a 1 based index (think lines or bytes in a file) and func1() requires a zero based index (arrays). Now, if EO is undefined, the following line will not work as required because the compiler is free to evaluate the value of the function parameters in any order and the programmer can do nothing to control them.

      $result = func1( $var++ ) op func2( $var );

      However, if he codes that as

      $temp1 = func1( $var++ ); $temp2 = func2( $var ); $results = $temp1 op $temp2;

      or

      $temp1 = func1( $var ); $temp2 = func2( ++$var ); $result = $temp1 op $temp2;

      besides the extra variables and statements required, the opportunity for overlapping the processing in func1() and func2() is lost because their invokations are now implicitly serialised by the statement ordering.

      Your earlier contention was that by having the EO undefined, the compiler can decide to run the code in parallel, but it cannot, because it has no way of knowing, and the programmer has no way of indicating, that the two routines do not have interdependacies.

      But if EO is defined, then by putting the two function calls in the same statement, and ordering them the way they are

      $result = func1( $var++ ) op func2( $var );

      the programmer is explicitly stating that they do not have interdependancies and *can* be run in parallel.

      If he doesn't want them to be run in parallel, he has the choice of placing them in serial statements, and they will not be.

      He can also depend upon each function receiving the correct parameters because the subexpressions from which those parameters are derived must be evaluated first, and in the order specified. The point of synchronisation is 'op', whatever that may be. At every stage, the programmer can control what happens, in what order, instructing the compiler what to do and when and also freeing the compiler to parallelise the fetching of the operands if it has that capability.

      No extra syntax is involved. Just a clear definition that allows the programmer to instruct the compiler, rather having to guess what it might do.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco.
      Rule 1 has a caveat! -- Who broke the cabal?
        But if EO is defined, then by putting the two function calls in the same statement, and ordering them the way they are
        $result = func1( $var++ ) op func2( $var );
        the programmer is explicitly stating that they do not have interdependancies and *can* be run in parallel.
        So, the point of having a defined EO is to allow the programmer to tell the compiler "the order of execution is defined here, so you're free to run it in parallel because it doesn't matter in which order they are executed"? But that would mean that if the order did matter, then you can't write the above expression. Despite the EO being defined.

        Let's get a bit less abstract, and use a concrete example. Suppose EO is defined, and for binary operators, it's left to right. You have a function that reads a single line from stdin:

        sub read_a_line {return scalar <STDIN>}
        Now you want to use that function to get the next two lines. Since EO is defined, you might think it's safe to write:
        my $two_lines = read_a_line() . read_a_line();
        But by your statement, this tells the compiler the two function don't have interdependancies, and can be run in parallel. But that could mean the invocation on the right hand side might get the first line, leaving the second line for the invocation on the left hand side of the concatenation operator. And that means the statement should have been written as:
        my $two_lines = read_a_line(); $two_lines .= read_a_line();
        But that's how you write them if the EO is undefined.

        If writing

        EXPR1 OP EXPR2
        tells the compiler that there are no interdependencies between EXPR1 and EXPR2, and that the compiler is free to parallellize them, you are saying that the order of execution doesn't matter. And hence, it may as well be undefined.

        BrowserUk, you're confusing most of us, I think. Defined EO implies serialisation, undefined EO implies parallelisable, and you keep stating it backwards.

        Yes, separate statements means serialise. The semicolon is a "sequence" point (as per the ANSI C definition) which means that all effects and side effects must be resolved from the expression previous to the sequence point before beginning resolution of the expression following that sequence point. There are other sequence points other than the semicolon (&&, ||, ?:, and maybe even ()). But the bottom line is that anything happening between sequence points is undefined, but from one sequence point to the next is always in code order.

        It's the very fact that having the EO left as undefined that the compiler says, "I trust the developer that there are no interdependancies, because I haven't told the developer how I'm going to resolve them." If you don't know that func1 is called before, after, or at the same time as func2, then you shouldn't be putting them in the same expression (between sequence points) if they have interdependancies.

        However, if you know that func1 is called prior to func2, then you also know that func2 is about to be called with a value of $var that is 1 more than func1 was called with, and you may depend on this. If you depend on this behaviour, the compiler cannot parallelise func1 and func2 because you expect the op to be a sequence point where all side effects of func1 are resolved prior to func2 being called.

        You just simply have the effects of defined EO backwards.

        $a = 1; $x = $a++ + ++$a;

        Let's say we did define EO as left-to-right. That means that $a++ would evaluate prior to ++$a. Thus, the compiler must finish evaluating (and storing) $a++ completely prior to beginning evaluation of ++$a. That means that the compiler must take $a (1), put it in the register, and increment the remote memory, then take $a again (now 2), increment it (now 3) and put it back into remote memory, and add the current value to the former value, and get $x = 4, $a = 3. That is the definition of serial processing.

        If, however, we leave the EO undefined, the compiler could start evaluating $a++ (e.g., load the number 1 into a register), then start evaluating ++$a (e.g., load the number 1 again into another register), continue evaluating ++$a (add one in the register, now 2), go back to evaluating $a++ (increment the value in RAM, not the register, to 2), go back to evaluating ++$a (store the new value 2 in RAM), and then finally add the two (registers) together. This would leave $a = 2, and $x = 3. Note how the compiler did evaluate this in parallel. The programmer said that there were no interdependancies, but was incorrect in that statement, and the undefined nature of the outcome is based solely on this ability of the compiler to parallelise the activity.

        Would you agree that Perl could only implicitly parallelise functions, methods or tied variables if they appear in the same statement?
        No. If you want to make a version of perl that works like that, fine. But that certainly doesn't need to be the case.
Re^23: Why is the execution order of subexpressions undefined?
by Anonymous Monk on Apr 15, 2005 at 14:36 UTC
    And so far, noone has offered a single good reason why EO should not be defined in Perl
    It is bad form to code like you want to. Just like goto. It makes the code ugly and hard to understand. But of course this point has been made a number of times already, you just choose to ignore it.

      Hey. If goto is bad, why is it in the language?

      It is rarely used, but it is there for those occasions when it is necessary, or easier or clearer.


      Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
      Lingua non convalesco, consenesco et abolesco.
      Rule 1 has a caveat! -- Who broke the cabal?
        Hey. If EOD is bad, why is it in the language?

        It is rarely used, but it is there for those occasions when it is necessary, or easier or clearer.

        The reason that the traditional goto is in Perl is that it makes it easier to port programs to Perl. See the a2ps2p utility. The lack of labelled loop control makes goto useful far more often in C, but in Perl you can always rewrite a given piece of code to not use goto and yet run identically algorithmically. (Knuth wrote a famous paper about this in the 70s.)

        Of course there is always the unexpected. I have seen exactly one (Switch) use of goto in Perl that I would consider justifiable.