Skip to main content
6 of 6
replaced http://mathematica.stackexchange.com/ with https://mathematica.stackexchange.com/

Great question. My first reaction is that this shouldn't happen. h appears explicitly inside the Module and it should be substituted with the localized equivalent, e.g. h$123, even if it is held:

Module[{h}, HoldComplete[h^2]]
HoldComplete[h$6992^2]

However named patterns in constructs such as Set and Rule are exempt from this substitution:

Module[{h}, Hold[h_ -> h^2]]
Hold[h_ -> h^2]
Module[{h}, Hold[f[h_] = h^2]]
Hold[f[h_] = h^2]

This is related to:

Until now I did not realize that this affected constructs without a Hold attribute. That is I knew that Module handles Function, SetDelayed, and RuleDelayed differently:

Module[{x}, Function[x, x^2]]
Function[x, x^2]
Module[{x}, f[x_] := x^2]
?f
f[x_] := x^2
Module[{x}, x_ :> x^2]
x_ :> x^2

This actually makes sense as the x is already being localized by these constructs and additional substitution by Module would only result in e.g.:

Function[x$123, x$123^2]

However in the case of Set or Rule, which do not have hold attributes, this is problematic, as these are not localizing constructs as correctly recognized by the syntax highlighter. Daniel Lichtblau wrote plainly:

No need to dance around this: it's a flaw in the implementation of the scoping mechanism. Set SetSystemOptions["StrictLexicalScoping" -> True]; and it gives 16.

So it seems that my first reaction was correct, and this shouldn't happen but does.


Further thoughts and exploration

Leonid comments below that Set and Rule are still scoping constructs. I do not contest this. As noted the difference is in the evaluation behavior controlled by hold attributes.

Let us ask the question:

  • How should the right-hand-side Symbols in Set and Rule be handled within Module?

The existing default behavior leaves both the LHS and RHS x unchanged in this case which results in the RHS instance evaluating to the global value of x if it exists:

Module[{x}, x_ -> x]

x_ -> x

However a slight change results in different behavior:

Module[{x, y}, x_ -> x y]
x$_ -> x$ y$748

Here the automatic renaming mechanism kicks in and changes x to x$ on both sides of the Rule.

If as in SetDelayed and RuleDelayed the RHS is not expected to immediately evaluate this difference in renaming often will not matter. However with Set and Rule where the RHS is expected to evaluate this inconsistency is troubling. One cannot generally rely on the behavior illustrated in the original question as it will break if this renaming is activated:

h = 5; i = 7;

Module[{h, i}, h_ -> h^2]

Module[{h, i}, h_ -> i*h]
h_ -> 25

h$_ -> h$ i$787

From a user's perspective the simple introduction of i in the RHS should not result in an entirely different evaluation characteristic, yet it does. (This affects Set as well.) It would be desirable to have consistency in this behavior, and it seems that is exactly what Daniel's System Option provides:

SetSystemOptions["StrictLexicalScoping" -> True];

h = 5; i = 7;

Module[{h, i}, h_ -> h^2]

Module[{h, i}, h_ -> i*h]
h$_ -> h$^2

h$_ -> h$ i$1334

Now the h is renamed to h$ on both sides of both rules.

Mr.Wizard
  • 273.1k
  • 34
  • 595
  • 1.4k