3. Defining Variables and Functions

Last revision:  January 15 1998

In this section we cover various ways to store a value or an expression in a variable (a place inside the computer) as well as ways to store a list of instructions inside a function.

Variable Declaration and Initialization: Set

We have already learned how to give a value a name: we decide on a consecutive sequence of letters (the "name"), follow it by a single equals sign, and then place the value on the right.  Let's consider this operation in a little more detail.  When we give Mathematica an instruction such as "mess = 7", Mathematica does several things.  First, Mathematica evaluates the right-hand side of the expression (yielding an Integer, 7).  Then Mathematica declares a new variable (by which we mean that Mathematica will remember from now on that a certain name is significant), named "mess". Then Mathematica assigns this variable an initial value, the Integer 7.  Finally, the result of our operation is whatever value was assigned, in this case 7, so Mathematica gives us a 7 back (in our Output cell).  From now on (unless we change "mess"), any time we use "mess", Mathematica will use the Integer 7.  We have made, then, a global declaration and have initialized the variable to the value 7. The word "global" refers to the fact that wherever we use the name now, it will always refer to the variable we have created; the word "initialized" indicates that, upon creation, it was first assigned a particular value, in this case the Integer 7.

Let's consider a few examples.

a = 20.71

b = a^2+a-1

Notice here that the value of "b" is not saved as "a^2+a-1", but as a Real value of around 448.614.   Remember, the right-hand side is evaluated first, and then the new value is assigned to the variable.

If we change the value of "a", the variable "b" will not change, as follows:

a = 19

b

We can ask Mathematica what it knows about a variable, or, for that matter, any "name".  Let's ask what it knows about "b":

?b

What Mathematica is telling us is that "b" is globally declared, and its latest value is 448.6141.

Functional Forms

In Mathematica, there are usually several ways to accomplish any operation.  For the value assignment operation we have performed above, we have an alternative functional form, Set[]. (Functional form refers to using a name with brackets to complete an operation, rather than using a special symbol, like the equals sign.)  Sometimes functions have expressions placed in between the brackets, and we call them arguments, or parameters.  If the number of arguments is greater than 1, then the arguments are separated by commas (as in "N[Pi,50]").  For our function Set[], the first argument is the name we want to declare and initialize.  The second argument is the value to which we want to initialize the name.  In short, then, "mess = 7" can be accomplished in functional form by evaluating "Set[mess,7]".  Remember that just as with the assignment operation using the equals sign, this second argument will be evaluated first before the assignment happens.

Set[a,20.71]

Finally, we consider one more example.

bigmess = Expand[(x+2)^10]

bigmess

All of the operators which we have seen have special functional forms.  Here is a list of the operators, together with their functional forms:

a>b    Greater[a,b]
a>=b   GreaterEqual[a,b]
a<b    Less[a,b]
a<=b   LessEqual[a,b]
a==b   Equal[a,b]
a!=b   NotEqual[a,b]
!a     Not[a]
a&&b   And[a,b]
a||b   Or[a,b]

Variable (Re)Assignment after Initialization

Once a variable, or any name, is declared and initialized, it may be redefined or reassigned.  Once we do so, Mathematica essentially forgets the first value, and from that point forward until another redefinition, the name will refer to the new value.

mess = 9

If we execute the statement above, then "mess" will then refer to the value 9, of Integer type.  Although this is the desired behavior, here is a caveat:  if we return to an earlier cell in our notebook and reevaluate each cell, we may get different answers than we did before.  For instance, if earlier cells included the instructions "mess=8" and "bigmess = mess^10", the first time we evaluate them we would find that bigmess is 8^10.  However, if we execute "mess = 9" and go back  to and reevaluate the second of the first two cells ("bigmess = mess^10"), then we will find that bigmess has changed to 9^10.

Modifying a Variable's Value with Arithmetic Operations

Frequently we will want to take a variable's value, do something simple to it, such as add 3 to it or multiply it by 4, and put the new value back into the variable.  We are, then, reassigning the value, based on the old value.  We can accomplish these operations using the equals sign just as before, remembering that the right-hand side is evaluated before  the assignment is made.  Consider the following cell:

mess = 10;
mess = mess + 10

(Note that the semicolon suppresses the output of the line on which it occurs and separates the two lines.)  What happens in the second line is that "mess + 10" is evaluated to the Integer 20, and then this is reassigned to "mess".  For the mathematically inclined, the statement "x=x+10" will seem an inconsistency, but for (we) computer programmers it is crucial to remember that the equals sign invokes an action (assignment) and does not claim an equality.  (Recall that the double equals sign "==" is the equality test.)

Here are some more examples of arithmetic value modification:

mess = mess * 10

mess = mess / 20

mess = 2 + 10 / 5 + mess / 2

There are other assignment operators which we will use from time to time, and these operators are essentially shorthand for longer expressions.   They are used when we want to take and old value of a variable, perform one arithmetic operation to it, and replace the value.  The operator "+=" adds the (evaluated) right-hand side to the variable on the left and reassigns it.  As an example:

mess = 8;
mess += 1

Other examples:

mess -= 1

mess *= (2+10)

mess /= 4

Of course, if we wish to assign a value to a variable based on other variables, then these shorthand operations will not help.  For instance, there is no shorthand for the following expression.

mess2 = mess * 2

For completeness' sake, here are the functional forms of these operators:

a+=b    AddTo[a,b]
a-=b    SubtractFrom[a,b]
a*=b    MultiplyBy[a,b]
a/=b    DivideBy[a,b]

Increment, Decrement, PreIncrement, PreDecrement

One very common way in which computer programmers change values of variables is to add 1 or subtract 1 from a variable; this is useful in loops, where we do a certain operation (say) 10 times.  In that instance we will need to initialize a variable to 1, add 1 each time we do the operation, and continue doing so until the variable reaches 10.  Adding one to a variable is called incrementing the variable, while subtracting one is called decrementing  the variable. There are some useful shorthand expressions for incrementing and decrementing, namely "++" and "--". You can use either one by placing it either immediately before or immediately after the name of the variable, as for instance "i++", "i--", "++i", and "--i".  As you might expect, "++" adds one (the Integer 1) to the variable, while "--" takes 1 away.

There is one subtle difference between placing a "++" or "--" expression before and placing it after the name:  when  the incrementing or decrementing happens.  If you put the "++" or "--" before  the variable, then the incrementing or decrementing happens before  the value is used in the current expression; if you place it after, then the incrementing or decrementing happens afterwards.

Let's look at some examples. Suppose "mess" starts out as 8:

mess = 8

Now let's add one to it and find the new value:

++mess

What happened is that we asked for the value of mess, but the "++" had to happen before the value was used in the evaluation of the line, so "mess" was incremented to 9 and then returned to us.  Now let's ask for the value of mess with a increment afterwards:

mess++

We still get 9, but "mess" is really now 10!  To convince ourselves of this, let's find out what mess is:

mess

What happened?  When we executed "mess++", the expression's value was that of "mess", which was 9, and after  the evaluation happened (and we were returned the value 9), mess was incremented. Then we asked for the value of "mess", and the expression "mess" evaluated to its new value, namely, 10.

Functional forms for the increment and decrement operators are as follows:

a++    Increment[a]
a--    Decrement[a]
++a    PreIncrement[a]
--a    PreIncrement[a]

We can always find the functional form for an expression by using the function "FullForm[]".  For instance, "FullForm[a<b]" will return "Less[a,b]".

Deassignment, Undeclaration

What if we want to get rid of a variable's value?  For instance, what if we want to have a polynomial "f" be the expression "x^2+x+1" and "x" has already been declared and initialized to the Integer 5?  Then if we set "f" to be "x^2+x+1" then we will get 31, not "x^2+x+1"!  One solution is to tell Mathematica to forget about the value of "x".  There are several ways to accomplish this, one of which is to use the function "Clear[]".  The function "Clear[]" erases the value of each name appearing as an argument to it.  For example:

mess = 9

Clear[mess]

mess

(A shorthand for Clear[mess] is "mess =."  Yes, include the period right after the equals.  Actually, "=." is a shorthand for the function "Unset[]", which is somewhat different from "Clear[]", but we will ignore the differences for now. The most powerful of Mathematica's undeclaration functions is "Remove[]".  When "Clear[]" erases a value, Mathematica still remembers that the name has been used somewhere (so that it is still declared); "Remove[]" instructs Mathematica to forget that it ever saw the name.)

Function Definition: SetDelayed

Let's think again about how we defined "b" above.  What if, instead of computing the value of (a^2) + a - 1 with the value of a which is currently defined, we wish to have Mathematica compute the value of the function (x^2) + x - 1 for any given value of x?  The best way to do this in Mathematica is to define a function.  A function typically has several arguments or parameters, and the function operates by taking the values it is given for those arguments and using them in some expression or sequence of operations.  When we define a function, we must give Mathematica a name for each of these parameters, but we must distinguish these names from the global names which we might already have declared.  Here's how to do it:  First, on the left-hand side of the function definition, when names for each argument are given between the brackets (separated by commas, as usual), attach an underscore ("_") immediately following each one. Second, instead of using "=", use colon-equals (":=", the delayed assignment operator ). For example:

Clear[f]
f[x_] := x^2 + x - 1

This line tells Mathematica several things.  First, it must declare a new name, "f"; second, this instance of "f" may take exactly one argument or parameter; third, if "f" is evaluated with an expression in between the brackets, that expression will (temporarily) be called "x"; finally, the function "f" will take this new "x" and use it in the expression on the right-hand side to provide an answer.  An important fact to remember is that, unlike the scenario with the assignment operator "=", the right-hand side is not evaluated at all.  Let's use "f":

f[2]

There are some terms appropriate here.  A formal parameter is a name assigned inside a function declaration to be used for one of the arguments of the function.  Formal parameters in Mathematica are distinct from global names.  In the case above, "x" is a formal parameter.  An actual parameter, on the other hand, is a value with which the function is actually evaluated.  In the case above, the "2" in "f[2]" was an actual parameter.  Actual parameters need not be Integers, of course; we can call "f" with anything we like inside the brackets:

f[y]	(* y is called an actual parameter *)

f[a]	(* a is called an actual parameter *)

f[7]	(* 7 is called an actual parameter *)

Even more, we can use "x" as an actual parameter, and Mathematica will realize that it is distinct from the formal parameter "x"!

f[x]	(* here, the x is an actual parameter *)

As you may have noticed, using "(*" and "*)" around some text in an input cell allows you to compose a comment that Mathematica will ignore.  When our code gets especially complicated, we will comment more often.

The functional form of the colon-equals operator is SetDelayed[].  The following two input cells are then equivalent:

Clear[myFunction]
myFunction[x_] := Sin[x] + Cos[x]

SetDelayed [myFunction[x_], Sin[x] + Cos[x] ]

In order to reinforce the need for underscores and the colon-equals sign symbol, let's look at what can happen when you don't do one or the other of our requirements.

Leaving Out the Underscore

If we leave out the underscore, Mathematica no longer sees the argument as a formal parameter into which any expression can be substituted.  Instead, it simply remembers the name of the function and decides that if the parameter is ever exactly  the one we specify, the function will return whatever right-hand side we wrote down.  For instance:

Clear[bad]

bad[x] := x^2 + x - 1

bad[x]

bad[y]

bad[7]

This is clearly not the behavior we want in a general function.

Using = Instead of := (Set Instead of SetDelayed)

If we use equals instead of colon-equals, Mathematica will immediately evaluate the right-hand side of the equals sign and then assign the resulting expression to our function.  While this sometimes produces the desired outcome, it can be a dangerous operation.  Consider the following sequence of steps:

x = 2
h[x_] = x^2+x+1

Mathematica has declared a function "h" which takes one formal parameter "x", but the expression the function will evaluate with "x" is not "x^2+x+1" but the Integer 7!  This example explains the meaning of the functional name "SetDelayed":  Mathematica delays   evaluating the right-hand side until after the function is used; it does not evaluate the right-hand side when the function is defined.  Let's convince ourselves that "h" has an undesirable definition:

h[1]

h[2]

h[y]

?h

It is certainly true that in our example above, evaluating the command "Remove[x]" before defining the function using the equals sign would have made "h" a well-defined function. However, there are situations in which deciding whether the equals sign will work can be quite delicate, and we hope that the first impulse will be to use colon-equals.

The Naming of Functions

One good programming principle is name the functions we create differently from functions which are basic to the programming language itself.  For instance, we probably shouldn't try to define our own function called "Plot[]".  Thankfully, Mathematica prevents us from doing so (by giving all of its own functions the "Protected" attribute, as we will see later). Still, we should distinguish our own functions from those of Mathematica by using a different convention in function naming:  we shouldn't capitalize the first letter of our function name.  We are free, however, to capitalize the first letters of successive words in the function name, in order to make their names more readable.  Some examples of good names for user-defined functions are "myFunction", "plotMyFunction", "takeMyDerivative", "initializeMyVariables".

One caveat is that, in Mathematica, functions can have the same names as variables, and if this happens, confusion erupts.  For instance, if we define "f[x_] := x^2" and then evaluate "f = x + 2", Mathematica will try to remember both.  Let's try it:

Clear[func,x]
func[x_] := x^2
func = x + 2

?func

Hence, to refer to the function defined above, it will be necessary to use brackets and put some expression between the brackets.  To plot the function "func", then, we must specify "func[x]", not "func", but if "func" is already defined separately as a variable, then Mathematica will make a mistake and try unsuccessfully to evaluate the expression "x+2[x]".  Notice that in the plot below we get a plot of "x+2", not "x^2":

Plot[func,{x,-1,1}]

The solution is never to have two expressions with the same name, and always to refer to a function using brackets.

Using Set for Function Definition (Beware.)

You may wish to skip this section for a while, maybe even for a week or two.  If you're unsure, just go ahead an close the cell group!  The purpose of this section is to show you that you may in fact want to use the assignment operator "=" to define a function.  We'll give two examples, one where to do so would make the situation easier, another where it would be a mistake.

Example 1: Where = is good

First, we introduce the derivative function "D[]", which differentiates the first argument with respect to the variable stated in the second argument.  (For the purposes of this example, we need only know that the derivative function applied to a polynomial returns another polynomial.)  Let's try to define a function finds the derivative of a certain polynomial (let's say x^2+x-1, for simplicity) and then substitutes a particular value for x inside the new polynomial. The parameter of our function, then, will be this particular value.  We might write

Clear[g]
g[x_] := D[-1+x+x^2, x]

But this would be a terrible mistake.  Why?  Because when we ask for, say, "g[3]" the value 3  would be substituted into the entire right-hand side everywhere there is an "x", and so Mathematica will try to evaluate "D[11,3]", which, first, doesn't make sense (since the second argument is not a variable) and, second, gives us an error.  What we want is to find the derivative (with respect to "x") first, and then evaluate at the value of "x".  We might try the following:

Clear[g]
deriv = D[-1+x+x^2, x];
g[x_] := deriv

Here we simply find the derivative, assign it to the name "deriv", and have "g" defined to use "deriv" as its right-hand side.  But this doesn't work either, since "g" is not defined as "1+2x" (the derivative of "-1+x+x^2"), but simply as "deriv".  We ask, why wasn't "1+2x" substituted for "deriv" in the second line?  Because SetDelayed (or ":=") doesn't evaluate the right-hand side before it defines the function.  To check,

?g

Now we are upset.  We can force Mathematica to evaluate "deriv" before it defines the function.  We can do so as follows:

Clear[g]
deriv = D[-1+x+x^2,x];
g[x_] := Evaluate[deriv]

To do this, however, is basically to walk a long way around the simpler expression, using "=", which does basically the same thing:

Clear[g]
g[x_] = D[-1+x+x^2,x]

Example 2:  Where = is bad

In this example, we use the "Random[]" function, which finds a random value of the type specified by the first argument, in an interval specified as "{begin, end}" in the second argument.  (For instance, "Random[Real,{0,1}]" produces a random approximate number between 0 and 1.  See "?Random" for more information.)  We wish to define a function taking one argument (say "n") which returns a random integer from 1 to the number we specify ("n").  If we try defining the function with the assignment operator "=" we certainly have a problem, since Mathematica tries to evaluate the right-hand side before assigning the definition to the name of our function, and at that point Mathematica doesn't know a value for "n":

Clear[rand,n];
rand[n_] = Random[Integer,{1,n}]

But if we use the delayed assignment operator ":=", all works out right.

Clear[rand];
rand[n_] := Random[Integer,{1,n}]

rand[100]

rand[50]