x = 10<p>y = x + ++x<p>What is y?<p>Even the professor who teaches compiler construction at my university thought it was interesting to see how different languages or compilers handle this. I've tried a couple but leave it to you to post and discuss your results.<p>(I know it's terrible code)
<p><pre><code> (let* ((x 10)
(y x))
(+ x (incf x)))
vs
(let* ((x 10)
(y x))
(prog1
(+ x x)
(incf x)))
[INCF does it with side-effects, use 1+ or directly evaluate (+ 1 x) for the clean version]
</code></pre>
Not everyone puts up with semantic ambiguity in operator precedence and evaluation. Some of us program in parse trees, directly :-)
<p><pre><code> val x = unsafePerformIO $ readIORef x
inc x = unsafePerformIO $ modifyIORef x (1+) >> readIORef x
main = do
x <- newIORef (10::Int)
print $ val x + inc x
</code></pre>
The result is 21.<p>Edit: an explanation. GHC runs on graph reduction, and will do "normal order" reduction in the normal case. + is strict in both arguments, so (val x) will be fully evaluated before (inc x) is evaluated.<p>If we replace with a lazy operator like (:), then we can get different results. Here is a program which will evaluate the (inc x) first:<p><pre><code> main = do
x <- newIORef (10::Int)
print $ reverse $ val x : inc x : []
</code></pre>
the expression is not fully evaluated until it is printed, and then it is evaluated in reverse order, so inc x runs before val x. The result is [11,11].<p>Of course, none of this can be relied on. GHC does a lot of optimizations, and unsafe operations are unsafe.
The formal answer for C and C++ is "undefined", because the + operator is not a sequence point (meaning that the side-effect of ++ may or may not flushed). So my favourite compiler would issue a warning :)
Interpreter, really:<p><pre><code> >>> x = 10
>>> x + ++x
20
</code></pre>
I suspect my other favorite compiler will say 'Type error: Could not match "Num a => a" against "Num a => [a] -> [a]"', but I don't want to wait for it to finish installing.
Think about how this is compiled. In machine language there are no nested expressions, so the compiler will have to split the expression up.<p><pre><code> expression( ... ++x ... )
</code></pre>
will probably be translated to<p><pre><code> x = x+1;
expression( ... x ... )
</code></pre>
This is the simplest way to compile ++x:<p><pre><code> 1. put x=x+1 before the expression
2. replace ++x with x
</code></pre>
So I think most languages would get 22.<p>But in languages where + is a function there's a good chance you get 21.
I would expect 22. On a related a aside this reminds me of a time in school where I wrote a recursive function that I called using the post decrement operator as follows, some_func(x--) which was supposed to stop recursion when x reached zero. Of course, it never did and went until it filled the stack. One of those things that stares you in the face and yet takes hours before you're like duh.
<p><pre><code> # let x = 10;;
val x : int = 10
# let y = x + ++x;;
Error: Syntax error
</code></pre>
Hmm. Let's try that again:<p><pre><code> # let x = ref 10;;
val x : int ref = {contents = 10}
# let y = !x + incr x;;
Error: This expression has type unit but an expression was expected of type int
</code></pre>
So nothing, I guess!
My favourite compiler, would have a manual one page long. I should be able to read it and program 'hello world' in five minutes. It should come with about 40 primitives and leave the rest to me and its community!(It should also throw an error if you type y=x + ++x<p>:)
y is 22. But my favourite imaginary compiler doesn't allow you to compile the second statement unless 1. your IQ is above a certain threshold 2. you explained in a comment - why?...