Re: sequence points
On Oct 15, 7:49 pm, Kai-Uwe Bux <jkherci...@gmx.net> wrote:
> Let me slightly modify the example so that all subexpressions have
> side-effects:
>
> int a = 0;
> int b = 0;
> a = ( ( a = 5 ), ( b = 4 ) );
>
> The comma operator introduces a sequence point that clearly separates
>
> a=5 from b=4
>
> The question at hand is whether this sequence point also separates
>
> a = rhs from a=5
The answer at hand is of course, yes - by transitivity: "b=4" is
evaluated after "a=5" due to the comma operator between them, whereas
"b=4" is evaluated before "a=rhs" because the evaluated value of "b=4"
is the "rhs" assigned to "a" to complete the expression. Therefore the
"a=rhs" assignment must occur after the "a=5" assignment - because we
know that the evaluation of "b=4" must take place after the latter and
before the former.
In C++, operands and operators guide the evaluation of an expression -
but do not mandate a single interpretation (like Java does). So
"sequence points" were invented as a way to describe just how much
leeway a C++ compiler does have when evaluating an expression - and by
the same token - to let a C++ programmer recognize when an expression
has granted too much latitude to the compiler and could therefore lead
to an unexpected result.
In this example, the semantics of the expression are as follows:
assign 5 to a as the left operand of the comma expression
assign b to 4 as the right operand of a comma expression
evaluate b=4 as 4
evaluate the entire comma expression to the right hand operand: 4
assign 4 to a
Next we can determine how much latitude the compiler has in following
this order. We know that assigning 5 to "a" must be done first (and
"a" must have the value 5) before proceeding to the next step
(courtesy of comma operator)
We know that right-hand side must completely evaluate to "4" before
"4" can be assigned to "a". We cannot be sure that "b" will have the
value "4" before "b=4" evaluates to 4 - but since there is nothing
that depends on whether a or b gets their assigned value first - the
uncertain order of the side effects on the right hand side of the
expression - makes no difference.
In short, the comma operator cleanly divides the evaluation and side
effects of "a=5" from the assignments and evaluations that follow it.
And there is no amount of lawyering that will get around that fact.
> On a more fundamental level, it is the very computational model of C++ about
> which I am not sure. It seems to me that there is an 'obvious'
> understanding: an expression specifies a computation, the computation has
> side-effect and yields a value. The value is not available to take part in
> other side-effect before it has been computed.
>
> However, there is also a 'counter-intuitive' reading of the standard: an
> expression specifies a computation. This computation establishes a value
> and can cause side-effect. However, the time at which side-effect takes
> place is independent of the actual establishment of the value. In
> particular, a conforming implementation could proceed as follows: For each
> expression, create (bottom-up starting with innermost subexpressions) a
> pair: (value, instruction_sequence) where the value is the value and the
> instruction_sequence can be executed to make all side-effects of the
> evaluation happen. Then, for each operator, we have a rule like these
>
> given lhs + rhs:
> find the pairs (lhs_value, lhs_sequence) and (rhs_value, rhs_sequence)
> the pair for lhs+rhs is:
> (lhs_value + rhs_value, shuffle( lhs_sequence, rhs_sequence) )
>
> given lhs = rhs
> find ( lhs_value, lhs_sesquence ) and ( rhs_value, rhs_sequence )
> the pair for lhs = rhs is:
> ( rhs_value, shuffle( lhs_sequence, rhs_sequence, {assignment} ) )
>
> given lhs, rhs
> the pair for lhs, rhs is:
> ( rhs_value, concat( lhs_sequence, rhs_sequence ) )
> ^^^^^^
>
> Note how the last rule will ensure that all side-effects of the left-hand
> side in a comma-expression take place before any side-effect of the
> right-hand side.
>
> If such an implementation was conforming, the comma sequence point would not
> separate the outer assignment from the inner.
But since a comma operator makes precisely that guarantee, this
implementation as described - would not be conforming.
Greg
|