Do you really need to return x
from your function (even as part of a larger expression)? There is simply no good way to do this if x
has a global value, as x = 1; x -> 2
immediately evaluates to 1 -> 2
.
You could return the solution value only (val
instead of x -> val
):
SolveIt[a_, b_] :=
Module[{x, soln},
soln = Solve[a x + b == 0, {x}];
x /. soln
]
SolveIt[3, 4]
(* {-(4/3)} *)
Using formal variable were mentioned. These have the advantage that they are Protected
, therefore they are guaranteed not to have an assigned value. So you might consider
Clear[SolveIt]
SolveIt[a_, b_] := \[FormalX] /. Solve[a \[FormalX] + b == 0, \[FormalX]]
SolveIt[3, 4]
(* {-(4/3)} *)
(Note: you can type \[FormalX]
using ESC $x ESC.)
But there is a big problem with this. This works fine:
SolveIt[a, 1]
(* {-(1/a)} *)
But what about this one?
SolveIt[\[FormalX], 1]
(* {-I, I} *)
We passed a symbol into the function, and that symbol happened to be already in use internally ... so we're solving the equation x^2 + 1 == 0
now (compare to a x + 1 ==0
before).
The same problem appears with Block
:
Clear[SolveIt]
SolveIt[a_, b_] :=
Block[{x, soln},
soln = Solve[a x + b == 0, {x}];
x /. soln
];
SolveIt[y, 1]
(* {-(1/y)} *)
SolveIt[x, 1]
(* {-I, I} *)
Thus it is important to use Module
(and not Block
or a formal variable) if you want to make it possible to pass symbols into the function. If you only pass in numbers, this is not a problem, but then you may consider defining the function as SolveIt[a_?NumericQ, b_?NumericQ]
.
In case you are not certain about the difference between Module
and Block
, see here:
In short, both localize variables, but Module
does this by renaming them to a unique name (so that x
becomes something like x$123
) while Block
just temporarily removed any definitions that may be associated with x
(but x
is still the same symbol as before). Module emulates lexical scoping and Block does dynamic scoping.
SolveIt[a_, b_] := \[FormalX] /. Solve[a \[FormalX] + b == 0, \[FormalX]]
. (It looks gnarly on SE, but should paste fine into Mathematica.) $\endgroup$x
has a value, it will evaluate immediately in an expression such asx -> 1
. There is just no good way to return something containingx
ifx
has a value. Do you really need to returnx
from the function (as part of a larger expression)? Or is it sufficient to return the solution as a number, i.e. returnval
instead ofx -> val
? $\endgroup$