A short answer
Despite some thoughts here, you can localize a pattern variable without switching to SetDelayed
:
ClearAll[f, x];
x = 1;
Module[
{y = 0},
f[x_] = x^(1 + 1) + y
];
??f
(*f[x$_]=x$^2*)
Mechanics behind this behavior
At this point I wish to thank Leonid Shifrin, for it is his posts here on SE that shed light on how scoping works in Mathematica for me.
I would point out three ideas about scoping in MMA:
Scoping is not connected directly to evaluation. These are two separate concepts.
Scoping is performed by replacing symbols that can cause conflicts with other symbols.
This replacement is performed by the outermost scoping construct as part of the evaluation of this outer scoping construct.
Symbols will be replaced only when there is an explicit possibility of a conflict.
Let's illustrate this ideas on examples.
Example 1
ClearAll[f, x];
x = 1;
Module[
{y = 0},
f[x_] = x^(1 + 1) + y
];
?? f
(*f[x$_]=x$^2*)
Here Module
detects that there is a local variable (y
) inside another scoping construct (Set
). To prevent a conflict, Module
renames x
to x$
.
Example 2
ClearAll[f, x];
x = 1;
Module[
{y = 0},
f[x_] = x^(1 + 1)
];
?? f
(*f[x_]=1*)
Here Module
doesn't see y
inside the definition and doesn't replace x
because there is no possibility of a conflict between x
and y
inside the inner scoping construct (Set
).
Example 3
ClearAll[f, x];
x = 1;
f[x_] := x;
?? f
(*f[x_]:=x*)
SetDelayed
is an outermost scoping construct here, so there is no need for SetDelayed
to rename its own local variables. But here rhs is not evaluated, so we keep x
rather than its "definition-time" value.
Example 4
ClearAll[f, x];
x = 1;
f[x_] = x;
?? f
(*f[x_]=1*)
Again, Set
here is an outermost scoping construct, so there is no need to replace its own symbols. But this time rhs is evaluated, so we keep a "definition-time" value of x
rather than the symbol itself.