To best show this, first I'll present a simple, zombie-free module:
In[1]:= a[b_] := Module[{c, d},
c[___] := (Print[c];);
d[___] := (Print[d];);
c[];
d[]
]
This works as expected:
In[2]:= a[1];
During evaluation of In[2]:= c$6797
During evaluation of In[2]:= d$6797
Also, the names in the context are as expected; in particular,
there are no temporaries in it:
In[3]:= Names[$Context <> "*"]
Out[3]= {"a", "b", "c", "d"}
The above is what I'd consider "standard operating procedure."
Now, before proceeding to the weirdness, I clear the context, for
good measure:
In[4]:= Scan[Remove, Names[$Context <> "*"]]
...and define another module, identical to the first one, except that
in this one I've added a condition to the last line:
In[5]:= a[b_] := Module[{c, d},
c[___] := (Print[c];);
d[___] := (Print[d];);
c[];
d[] /; b === 1
]
The module's behavior is, again, as expected:
In[6]:= a[1];
During evaluation of In[6]:= c$6798
During evaluation of In[6]:= d$6798
The weirdness is in the context's names:
In[7]:= Names[$Context <> "*"]
Out[7]= {"a", "b", "c", "c$", "d", "d$", "d$6798"}
Now we have lingering temporary variable zombies! Not only
"stubs" (is this what they're called) like c$ and d$, but also a
full-blown d$6798. Here are their definitions:
In[8]:= {#, ToString[Definition[#]]} & /@
Select[%, MemberQ[Attributes[#], Temporary] &] // ColumnForm
Out[8]= {"c$", "Attributes[c$] = {Temporary}"},
{"d$", "Attributes[d$] = {Temporary}"},
{"d$6798", "Attributes[d$6798] = {Temporary}\n \nd$6798[___] := (Print[d$6798]; )"}}]
FWIW, the zombies appear only when the condition in the last line
is True (leading to the evaluation of the rest of the last line):
In[9]:= a[2];
During evaluation of In[9]:= c$6799
In[10]:= Names[$Context <> "*"]
Out[10]= {"a", "b", "c", "c$", "d", "d$", "d$6798"}
Note that after evaluating a[2] we see no zombie for d$6799.
Nevertheless, every time the condition is true, the context gets
littered with one more zombie:
n[11]:= a[1];
During evaluation of In[11]:= c$6800
During evaluation of In[11]:= d$6800
In[12]:= Names[$Context <> "*"]
Out[12]= {"a", "b", "c", "c$", "d", "d$", "d$6798", "d$6800"}
What's going on? And, more importantly, how can I redefine the
module in In[5] so that its behavior remains unchanged, but it does
not litter the context with a trail of zombies?
Thanks!
~kj
I discovered a shockingly simple workaround to the problem I reported
in the original post of this thread: just use Block instead of
Module!
n[1]:= a[b_] := Block[{c, d},
c[___] := (Print[c];);
d[___] := (Print[d];);
c[];
d[] /; b === 1
];
In[2]:= a[1];
During evaluation of In[2]:= c
During evaluation of In[2]:= d
In[3]:= a[2];
During evaluation of In[3]:= c
In[4]:= Names[$Context <> "*"]
Out[4]= {"a", "b", "c", "d"}
(Granted, this may be only a workaround rather than a full solution.
It all depends on whether what I reported originally was "a bug or
a feature". If it was a bug (and an undocumented behavior of
lingering tempvar zombies sure looks like a bug to me), then the
fix can be done only by Wolfram's personnel.)
As an unexpected bonus, this solution *also* fixes something that
was a minor vexation: the extra junk (e.g. $1234) at the end of
variable names printed from within Module.
This is a rare occurrence indeed: a fix to one problem that also
fixes another problem that was (at least in my mind) entirely
unrelated to the first one.
~kj
On Sat, Dec 4, 2010 at 6:12 AM, kj <no.e...@please.post> wrote:
> I discovered that defining a Module in a certain way causes results
> in lingering temporary variable "zombies".
>
>
> To best show this, first I'll present a simple, zombie-free module:
>
> In[1]:== a[b_] :== Module[{c, d},
> c[___] :== (Print[c];);
> d[___] :== (Print[d];);
> c[];
> d[]
> ]
>
>
> This works as expected:
>
> In[2]:== a[1];
> During evaluation of In[2]:== c$6797
> During evaluation of In[2]:== d$6797
>
>
> Also, the names in the context are as expected; in particular,
> there are no temporaries in it:
>
> In[3]:== Names[$Context <> "*"]
> Out[3]== {"a", "b", "c", "d"}
>
>
> The above is what I'd consider "standard operating procedure."
>
> Now, before proceeding to the weirdness, I clear the context, for
> good measure:
>
> In[4]:== Scan[Remove, Names[$Context <> "*"]]
>
>
> ...and define another module, identical to the first one, except that
> in this one I've added a condition to the last line:
>
> In[5]:== a[b_] :== Module[{c, d},
> c[___] :== (Print[c];);
> d[___] :== (Print[d];);
> c[];
> d[] /; b ====== 1
> ]
>
>
> The module's behavior is, again, as expected:
>
> In[6]:== a[1];
> During evaluation of In[6]:== c$6798
> During evaluation of In[6]:== d$6798
>
>
> The weirdness is in the context's names:
>
> In[7]:== Names[$Context <> "*"]
> Out[7]== {"a", "b", "c", "c$", "d", "d$", "d$6798"}
>
>
> Now we have lingering temporary variable zombies! Not only
> "stubs" (is this what they're called) like c$ and d$, but also a
> full-blown d$6798. Here are their definitions:
>
> In[8]:== {#, ToString[Definition[#]]} & /@
> Select[%, MemberQ[Attributes[#], Temporary] &] // ColumnForm
>
> Out[8]== {"c$", "Attributes[c$] == {Temporary}"},
> {"d$", "Attributes[d$] == {Temporary}"},
> {"d$6798", "Attributes[d$6798] == {Temporary}\n \nd$6798[_=
__] :== (Print[d$6798]; )"}}]
>
>
> FWIW, the zombies appear only when the condition in the last line
> is True (leading to the evaluation of the rest of the last line):
>
> In[9]:== a[2];
> During evaluation of In[9]:== c$6799
>
> In[10]:== Names[$Context <> "*"]
> Out[10]== {"a", "b", "c", "c$", "d", "d$", "d$6798"}
>
>
> Note that after evaluating a[2] we see no zombie for d$6799.
>
> Nevertheless, every time the condition is true, the context gets
> littered with one more zombie:
>
> n[11]:== a[1];
> During evaluation of In[11]:== c$6800
> During evaluation of In[11]:== d$6800
>
> In[12]:== Names[$Context <> "*"]
> Out[12]== {"a", "b", "c", "c$", "d", "d$", "d$6798", "d$6800"}