Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to globally turn off shadowing messages (symbol::shdw)? Or any other 'good practice' suggestions?

I have the following situation:

On[t::shdw]

Message[t::shdw,"t","Foobar","Dork"]
-> t::shdw: Symbol t appears in multiple contexts Foobar; definitions in context Dork may shadow or be shadowed by other definitions. >>

Off[t::shdw]
Message[t::shdw,"t","Foobar","Dork"]
-> **No Warning**

<<MASStoolbox`
-> t::shdw: Symbol t appears in multiple contexts {MASStoolbox`MASS`,Global`}; definitions in context MASStoolbox`MASS` may shadow or be shadowed by other definitions. >>

How can that be? Does On and Off only affect the current Notebook and have no effect when loading packages? If so, how can one get rid of messages like these? How should shadowing errors be treated?

like image 403
phantomas1234 Avatar asked Aug 23 '11 16:08

phantomas1234


1 Answers

The reason for what you observed is that the statement Off[t::shdw] disables a shadowing message for the symbol t that is currently on the $ContextPath, but not for another t, created during the loading of another package. You should disable shadowing message for that second t, if you don't want to see it. Here is an example:

In[1]:= Off[Test1`a::shdw]
In[2]:= 
BeginPackage["Test`"]
a
EndPackage[]

Out[2]= Test`
Out[3]= a

In[5]:= BeginPackage["Test1`"]
a
EndPackage[]

Out[5]= Test1`
Out[6]= a

Here, no message was generated.

Generally, however, I would not want to disable shadowing messages, since shadowing is a serious problem. Shadowing simply means that there is more than one context currently on the symbol search path ($ContextPath), containing symbol(s) with the same (short) name. Basically, if symbol is shadowed, and you refer to it by its short name (that is, symbol without its containing package), you have no guarantee which of the several symbols with the same short name will actually be used. So, the correct way to deal with this is to avoid shadowing altogether, which is always possible, if not always convenient.

The simplest way to avoid shadowing is to load the package you need into the private section of your package, which starts after the line Begin["`Private`"]. You do that by calling Needs[your-package], as always. In this way, the context of the loaded package does not stay on the $ContextPath together with your package's context. The worst case is when you need to load two packages with conflicting symbols. One way out is to construct a wrapper package for one of them, which would load that one privately and rename the conflicting symbols. This may be inconvenient though, since you'd have to rename all functions in a package, even those that don't conflict. Here is an example of a more flexible variant:

First package:

BeginPackage["Test`"];
g[x_?NumericQ] := x^2;
EndPackage[];

Second package:

BeginPackage["Test1`"];
g[x_?NumericQ] := x^3;
EndPackage[]

Main package:

BeginPackage["Main`"];
f::usage = "A test function of a single  argument";
Begin["`Private`"];

Block[{$ContextPath = $ContextPath},
  Needs["Test`"];
  (* Define first delegate private function *)
  g1 = Symbol["g"]];


Block[{$ContextPath = $ContextPath},
  Needs["Test1`"];
  (* Define second delegate private function *)
  g2 = Symbol["g"];
];

f[x_] := g1[x]*g2[x]
End[]
EndPackage[]

Now, provided that the system knows where to find your packages:

In[2]:= Needs["Main`"]

In[3]:= f[x]
Out[3]= Test`g[x] Test1`g[x]

In[4]:= f[2]
Out[4]= 32

And we used two conflicting symbols for the same public function. Using Block above served to localize the code where the first or second definition of g is used. Note that there is some inconvenience with this method in that we need to use Symbol["your-symbol-name"], to delay the parsing until run-time.

A much simple method is to just refer to symbols by their long names. In the above, we could just use Test`g and Test1`g and then there is no need for the heavy machinery. This is somewhat less flexible however, since you have to "hard-code" the symbol's context into the code.

like image 177
Leonid Shifrin Avatar answered Sep 28 '22 08:09

Leonid Shifrin