9
$\begingroup$
BeginPackage["First`"];
    symbol;
EndPackage[];

BeginPackage["Second`"];
    (*This block could be replaced with Needs @ "Internal`" in real life*)
    BeginPackage["Internal`"]; 
        symbol;
    EndPackage[];
EndPackage[];

symbol::shdw: Symbol symbol appears in multiple contexts {Internal`,First`}; definitions in context Internal` may shadow or be shadowed by other definitions.

I find it annoying because Internal` won't be on $ContextPath at the same time as First`. I don't want to switch this message Off.

Is it a bug or a feature? It should be possible to only investigate the previous state of the context path stack, or did I miss something?

$\endgroup$
3
  • 2
    $\begingroup$ I used Quiet when I encountered the same issue. github.com/szhorvat/LTemplate/blob/master/LTemplate/… It affects LTemplate like this: LTemplate can be loaded on its own, but it can also be embedded into another package (IGraph/M is based on it). If it was already loaded on its own, then a package that embeds it was loaded afterwards, then a shadowing message would be issued. $\endgroup$
    – Szabolcs
    Feb 12, 2019 at 15:18
  • 6
    $\begingroup$ It seems to be a bug. There have been internal discussions about this. Very annoying indeed. Hopefully it will be addressed soon enough. $\endgroup$ Feb 12, 2019 at 15:35
  • $\begingroup$ Any news about this? Seems to still be present in the newest version. Is there any other workaround than Quiet? $\endgroup$ Feb 15, 2022 at 22:44

1 Answer 1

1
$\begingroup$

This is definitely a bug as the docs General::shdw entry makes clear- (with the following emphasis added):


This message is generated when symbols with the same name occur in more than one context and both contexts are in the context search path.


In the OP's example, nowhere in the control flow do the contexts Internal` and First` together appear on the context search path. But the bug is in fact much more pernicious since it applies not only to "shadowed" package symbols but also to global symbols! Take the following:

symbol;

BeginPackage["Outer`"];
BeginPackage["Inner`"];
symbol;
EndPackage[];
EndPackage[]

(* shadowing message generated :( *)

enter image description here

This is kind of wild because what it means is that every single private package symbol ever created sets up the potential of a superfluous, distracting and discombobulating message, for any same-named symbol that has been previously constructed including for any symbols an end-user might have defined prior to loading your package--a very basic failure of encapsulation in the language. In fact, it is surprising to me that this hasn't reared its ugly head more often which I guess says something about the levels of a) package construction in the community b) use of private packages and c) naming practices currently adopted.

Quit

A "non-Quiet" workaround can be to turn off the specific shadowing message by bookending the offending symbols as they are created:

symbol;

BeginPackage["Outer`"];
Begin["`Private`"];
earlierCode;
Off[Inner`symbol::shdw]; (* to avoid Inner`symbol shadowing *)
BeginPackage["Inner`"];
symbol;
EndPackage[];
On[Inner`symbol::shdw]
End[];
EndPackage[]

(* no message generated :) *)

which at least seems somewhat more digestible when appearing in practice:

BeginPackage["Outer`"];
Begin["`Private`"];
earlierCode;
Off[Inner`symbol::shdw]; (* to avoid Inner`symbol shadowing *)
Needs["Inner`"];
On[Inner`symbol::shdw]
End[];
EndPackage[]

(* not to be evaluated but hypothetically; no message generated :) *)

There are however, two things to keep in mind for this workaround to be robust. Firstly, it needs to be established that earlierCode does not contain any appearances of symbol as any naming conflicts won't now be picked up and secondly, it needs to be established that downstream, the Inner` package itself is not calling any packages that also have symbol as one of their exports since likewise this naming conflict won't now be picked up. These however, seem to be fairly reasonable, often readily verifiable assertions (i.e. by following capitalization conventions in package exports etc.).

Quit

Hence in the OP's example the workaround becomes:

BeginPackage["First`"];
symbol;
EndPackage[];

BeginPackage["Second`"];
(*This block could be replaced with Needs@"Internal`" in real life*)

Off[Internal`symbol::shdw];
BeginPackage["Internal`"];
symbol;
EndPackage[];
On[Internal`symbol::shdw];
EndPackage[];

(* no shadowing message generated :) *)

But of course, none of this resolves the aforementioned perniciousness of this overall "shadowing" being flagged for all "private package" exports and clearly this workaround is not a scalable solution.

Even accepting the importance of fixing this bug, it is true that sometimes it is useful to know when a same-named package symbol has been previously created as it is invariably beneficial to remove code replication where it exists (and which is going to be much more likely for a package export than say, the extent to which such replication arises for same-named local variables in encapsulating constructs like Block, With, Module etc.).

Hence in fixing this bug, it would be helpful to also have access to new functionality like say:

On["PrivatePackageShadowing"]

(* suggestion only, not functional code *)

from which, if desired, the previous detection can continue to occur during development before being switched off prior to deployment.

$\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.