# Order of evaluation - does Mathematica evaluate variables before or after substitution?

Let's say I write

y = x^2;
x = 10;
z = y + y^2 + y^3


Does Mathematica internally evaluate y before or after substituting it into z? I.e., does Mathematica internally evaluate this as

y = x^2 = 100
z = 100 + 100^2 + 100^3 = 1010100


or as

z = (10^2)^2 + (10^2)^3 + (10^2)^4 = 1010100


? Obviously in this simple case it doesn't really matter, but if y is an expensive function to calculate, then the former order of evaluation could be much faster than the latter. In general, if I have intermediate variables that are expensive to calculate, will I get a speedup if I exchange the order of the first two lines of code?

• Each symbol can have a value associated with it or not. When you write y=x^2, then later on, write x=10, then y now automatically becomes 100 since it was pointing to x before, but now x has a value which is 10. There is no explicit evaluation of y. It is done automatically. It is all linked lists. If a symbol x has value other than itself, then its value is used automatically when looking up y. – Nasser Jan 11 '16 at 8:04
• @Nasser this is exactly what OP is asking about. Are dependencies between rules automatically eliminated, or not? It seems that the answer is not, in most cases anyway. This reminds me of another question, but I can't put my finger on it at the moment. – Oleksandr R. Jan 11 '16 at 8:42
• Aside: Mathematica is holding onto the symbolic definition of y = x^2. If you clear x the value of y will be x^2 not 100. If you had defined x=10 first then the value of y would be 100 before and after x is cleared. – Ymareth Jan 11 '16 at 9:03
• reference.wolfram.com/language/tutorial/Evaluation.html – Kuba Jan 11 '16 at 9:33

Try Trace:

    Trace[y = x^2;
x = 10;
z = y + y^2 + y^3]


From this result it looks like the second variant takes place.

Have fun!

Yes, x^2 is computed three times. One way to see it is this:

In:= On[]

On::trace: On[] --> Null.

In:= y = x^2

2      2
Set::trace: y = x  --> x .

2
Out= x

In:= x = 10

Set::trace: x = 10 --> 10.

Out= 10

In:= z = y + y^2 + y^3

2
y::trace: y --> x .

x::trace: x --> 10.

2       2
Power::trace: x  --> 10 .

2
Power::trace: 10  --> 100.

2
y::trace: y --> x .

x::trace: x --> 10.

2       2
Power::trace: x  --> 10 .

2
Power::trace: 10  --> 100.

2        2
Power::trace: y  --> 100 .

2
Power::trace: 100  --> 10000.

2
y::trace: y --> x .

x::trace: x --> 10.

2       2
Power::trace: x  --> 10 .

2
Power::trace: 10  --> 100.

3        3
Power::trace: y  --> 100 .

3
Power::trace: 100  --> 1000000.

2    3
Plus::trace: y + y  + y  --> 100 + 10000 + 1000000.

Plus::trace: 100 + 10000 + 1000000 --> 1010100.

2    3
Set::trace: z = y + y  + y  --> z = 1010100.

Set::trace: z = 1010100 --> 1010100.

Out= 1010100

In:= Off[]


I find this easier to follow than Trace but it produces too much junk in recent versions when run in the front end, so I had to run it in a terminal.

This observation does not imply that the result of y -> x^2 -> 10^2 -> 100 is not cached! (I don't know if it is.)

You can re-assign y form x^2 to simply100as simply asy = y in this case. Better, you could make it a function and use memoization to cache the result:

Clear[y]
y[x_] := y[x] = x^2


Yes, it seems the order can matter, at least when using SetDelayed (:=), which is common for functions. In that case, if you swapped the first two lines, it would indeed go faster.

One way to see this is with a very inefficient function, which calculates Fibonacci numbers the long way:

slowFib[n_] := If[n <= 2, 1, slowFib[n - 1] + slowFib[n - 2]];


On my machine, it takes about 3.2 seconds to calculate the 29th Fibonacci number this way:

slowFib // AbsoluteTiming
(*  {3.23395, 514229}  *)


Here is a slow calculation, with the same ordering as your example code. It takes 9.7 seconds to run the last line, because it is running slowFib 3 times to calculate y1:

y1 = slowFib1;
slowFib1 = slowFib;
z1 = y1 + y1 + y1 // AbsoluteTiming
(*  {2.*10^-6, slowFib1}
{1.*10^-6, slowFib}
{9.65774, 1542687}  *)


Compare this to a "fast" version with the first 2 lines swapped. It calculates the value of slowFib just once, when it assigns the value to y2, so it only does so once, and takes 3.3 seconds total:

slowFib2 = slowFib ) // AbsoluteTiming
(y2 = slowFib2) // AbsoluteTiming
(z2 = y2 + y2 + y2) // AbsoluteTiming
(*  {1.*10^-6, slowFib}
{3.28709, 514229}
{4.*10^-6, 1542687}  *)


What's going on here is that Mathematica only evaluates slowFib when it is called. In the fast code (vesion 2), it gets called once when defining y2. In the slow code (version 1), it gets called thrice, when defining z1.

• Indeed, I just tried swapping the order of the definitions in my actual application (much more complicated than the example in the OP) and got a significant speedup. – tparker Jan 11 '16 at 8:58
• If you are only evaluating your functions at a few values, take a look at tip #5 on this list: write your expensive functions as f[x_]:=f[x]=…`, so that values get saved as you go. – Seth Jan 11 '16 at 9:03

I'm not sure that memoization applies to OPs question. In a direct test, the order doesn't seem to make much of a difference in execution time. 