16
$\begingroup$

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.

enter image description here

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.

enter image description here

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.

enter image description here

$\endgroup$

4 Answers 4

18
$\begingroup$

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.

$\endgroup$
7
  • $\begingroup$ You probably meant Module[{a}, Subscript[a, 1] = "x"] in place of Module[{Subscript}, Subscript[a, 1] = "x"]? $\endgroup$ Jan 28, 2012 at 16:30
  • $\begingroup$ @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. $\endgroup$
    – Szabolcs
    Jan 28, 2012 at 16:40
  • $\begingroup$ 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). $\endgroup$ Jan 28, 2012 at 17:05
  • $\begingroup$ @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. $\endgroup$
    – Szabolcs
    Jan 28, 2012 at 17:08
  • $\begingroup$ Perhaps. +1 either way. $\endgroup$ Jan 28, 2012 at 17:17
7
$\begingroup$

Module only works with Symbols.

Head[ Subscript[a, 1] ]
Subscript

Perhaps you can use Internal`InheritedBlock or Internal`LocalizedBlock.

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

Internal`InheritedBlock[{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:

Internal`InheritedBlock[{Subscript},
  DownValues[Subscript]
]

Internal`LocalizedBlock[{Subscript[a, 1]},
  DownValues[Subscript]
]
{HoldPattern[a1] :> "x",  HoldPattern[a2] :> "y"}

{HoldPattern[a1] :> System`Private`$Localized, HoldPattern[a2] :> "y"}
Internal`InheritedBlock[{Subscript},
 Subscript[a, 1] = "x";
 DownValues[Subscript]
]

Beware that neither function actually works like Module:

Internal`InheritedBlock[{Subscript},
 Subscript[a, 1] = "new";
 foo
]

Internal`LocalizedBlock[{Subscript[a, 1]},
 Subscript[a, 1] = "new";
 foo
]
"new"

"new"
a := "old"
b := a
Module[{a = "new"}, b]
"old"
$\endgroup$
5
$\begingroup$

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

enter image description here

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

$\endgroup$
3
$\begingroup$

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}
$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.