Equal, Delayed Equal, and HoldAll Explained

This notebook will guide you through understanding the differences between Equal (=) and Delayed Equal (:=). It will also give a brief introduction
to the HoldAll attribute and try to describe when Evaluate should be used.

Equal and Delayed Equal (Set and Set Delayed)

The Set and Set Delayed functions may seem similar and in some cases they will produce the same results. In the following, Set is used to
assign a value to x and Set Delayed is used to assign a value to y. As we can see, when evaluated, x and y will evaluate similarly.

x = 3

?x

3 x

y := 3

?y

3 y

Clear[x, y]

However, in cases such as this, it is usually better to use Set to assign the value, as nothing will be gained by using Set Delayed. In fact, 
using Set Delayed will actually cause your program to execute slower, as every time y is seen within a calculation it will be re-evaluated.
Though this delay may not be noticeable in smaller programs, as your programs become more complex you may begin to notice some
delay being introduced.

Now we'll take a look at an example for which Set and Set Delayed produce differing results.

x = 3

f = 4 x

f

g := 4 x

g

So far these two definitions seem to work the same, but now let's take a look at the information for the variables f and g.

?f

?g

As we can see, these definitions differ slightly, but as the following shows it can produce a large difference in how your program functions.
When a new value is assigned to x and we re-evaluate f and g we get the following:

x = 10

f

g

Clear[x, f, g]

The slight difference in defining the functions has created a large difference in how the variables f and g evaluate. The reason for this difference is that
Set defines the variable f immediately using the information available at the time, whereas Set Delayed tells g to hold the assigned definition. This means
that every time g is evaluated the definition will be re-evaluated unlike f which will keep the same value until you alter it. So for numerical values you will
mostly want to use Set (=) and for functions Set Delayed (:=).

Introduction to HoldAll and Evaluate

Functions such as Plot and Block have the attribute HoldAll, we can see this by entering the following:

Attributes[Plot]

Attributes[Block]

What this means is that all input to the function will be held in an unevaluated form. So lets say we want to set the variables xlims
to be the plot range over which we will plot (x^3).

xlims  =  {x, -10, 10}

Plot[(x^3), xlims]

The reason that this does not work is that xlims is not being evaluated and the value xlims is being passed on to the Plot function
as the range specification. In order to get around this problem we need to use the Evaluate command to make xlims return the proper values.

Plot[(x^3), Evaluate[xlims]]

Clear[xlims]

Doing so, we see that the plot work correctly. The Evaluate command can be used to escape a HoldAll, but in some cases this will result in
incorrect output. Say we want to make a Block statement like the one that follows.

x = 1

y = 2

z := Block[{x = 3, y = 4}, x y]

?z

z

Giving the information on z we will note that the Block is being held unevaluated since we used the Set Delayed operator.
We will also note that x y is the body of the block. Now lets see what happens when we use Evaluate within the Block's
body.

zz := Block[{x = 3, y = 4}, Evaluate[x y]]

?zz

So far it looks as though it's functioning the same, but then we tell Mathematica to Evaluate zz and get:

zz

So why does zz return 2 instead of 12? The answer to this is rather simple. By adding the Evaluate around the x y
we tell Mathematica to Evaluate x y before executing the Block function. This causes x y to be evaluated before
the local environment set up by Block is created, and thus the values used for x and y are the global values, so you
will want to avoid using Evaluate within Block unless you want to use the Global variables within the calculation.

Clear[x, y, z, zz]