# Subscripts - Why do I see the error “only assignments to symbols are allowed” when using a Module and not otherwise?

When I type

Remove["Global*"]
foo[] := Module[{Subscript[a, 1] = "x"}, 0];
foo[]


I get the expected error "only assignments to symbols are allowed". I understand the error.

But why I do not get the same error when I type the same assignment in the notebook?

Remove["Global*"]
Subscript[a, 1] = "x"


No error and no beep.

What is the difference? I'm using version 8.04 on Windows.

## Update

The non-localized trick shown by Szabolcs answer worked for me on a demo. Here is a screen shot of the result. What I was trying to do is to typeset some information about a solver, some matrix equation, and I thought why not take advantage of MatrixForm and Grid's nice way of typesetting things, and display the information right there in the demo screen as an option? This is easier than putting it in the text section below where it can hard to get to as I have so many such things.

Here is an example of the code and the result. You can see I did not localized these symbols in the module which builds this expression. I just started trying this idea, but so far I am happy that it worked. This below is only an example, not cleaned up, just wanted to see if the demo will work.

This is because only symbols can be localized by Module. It is not about assignment, but localization.

Subscript[a, 1] is not a symbol, but a compound expression, so:

Module[{Subscript[a, 1] = "x"}, 0] (* <-- not allowed *)

Module[{}, Subscript[a, 1] = "x"]  (* <-- allowed but not localized *)


I agree that the error you got may be a bit confusing.

A somewhat ugly workaround is Module[{Subscript}, Subscript[a, 1] = "x"] or you may try to use the Notation package to create symbol names with subscripts in them. A word of warning though: in some cases, Module variables that have DownValues do not get destroyed when the Module finishes evaluating. For more information, see the end of the Module section in this answer by Leonid Shifrin, and the comments on that answer.

• You probably meant Module[{a}, Subscript[a, 1] = "x"] in place of Module[{Subscript}, Subscript[a, 1] = "x"]? – Leonid Shifrin Jan 28 '12 at 16:30
• @Leonid No, I meant what I wrote, and I agree that it is a hack. But it allows both displaying subscripted variables as such, localization, and usage in a Manipulate. If we write Module[{a}, Subscript[a, 1] = "x"], that'll be leaky. Module[{Subscript}, Subscript[a, 1] = "x"] renames subscript, and won't leak so easily. – Szabolcs Jan 28 '12 at 16:40
• It won't be more leaky (assuming you meant garbage collection), in this case. Referencing symbols in UI components is enough to prevent their collection, since UI components by themselves are global objects (they are expressions interpreted in a certain way by the Front-End). – Leonid Shifrin Jan 28 '12 at 17:05
• @Leonid Yes, I remember when we talked about Temporary symbols with DownValues not always getting collected. But I think in many use cases these would not need to be referenced. – Szabolcs Jan 28 '12 at 17:08
• Perhaps. +1 either way. – Leonid Shifrin Jan 28 '12 at 17:17

Module only works with Symbols.

Head[ Subscript[a, 1] ]

Subscript

Perhaps you can use InternalInheritedBlock or InternalLocalizedBlock.

Subscript[a, 1] = "x";
Subscript[a, 2] = "y";
foo := Subscript[a, 1]

InternalInheritedBlock[{Subscript},
Subscript[a, 1] = "new";
DownValues[Subscript]
]

Subscript[a, 1]

{HoldPattern[a1] :> "new", HoldPattern[a2] :> "y"}

"x"

Note the different syntax and starting value within each Block:

InternalInheritedBlock[{Subscript},
DownValues[Subscript]
]

InternalLocalizedBlock[{Subscript[a, 1]},
DownValues[Subscript]
]

{HoldPattern[a1] :> "x",  HoldPattern[a2] :> "y"}

{HoldPattern[a1] :> SystemPrivate\$Localized, HoldPattern[a2] :> "y"}
InternalInheritedBlock[{Subscript},
Subscript[a, 1] = "x";
DownValues[Subscript]
]


Beware that neither function actually works like Module:

InternalInheritedBlock[{Subscript},
Subscript[a, 1] = "new";
foo
]

InternalLocalizedBlock[{Subscript[a, 1]},
Subscript[a, 1] = "new";
foo
]

"new"

"new"

a := "old"
b := a
Module[{a = "new"}, b]

"old"


It's just a mattern of Module's syntax. You'll see that the message was generated from Module and not from Set (=)

Note

In fact, Set doesn't even seem to be called internally when you run a regular Module (even though Trace suggests it does)

We disable Set but it still works

In[42]:= ClearAll[x, y];
Block[{Set},
Module[{x = 8},
y = 9;
{x, y}
]]

Out[43]= {8, y}


In addition to the explanations above you can avoid this by using the Notations` package. Cut and pasting code would be confusing I think -- things don't seem to paste as I would like them too -- so I'll paste the screen grab

So now the subscripted variable is recognized as a symbol and the problem goes away.