3
$\begingroup$

Let us suppose we have two packages: A and B.

BeginPackage["A`"]

Foo::usage="bla bla";

Begin["`Private`"]

Foo[x_]:= x^2;
SetAttributes[Foo,{Protected,ReadProtected,Locked}];

End[]
EndPackage[]

.

BeginPackage["B`"]

Foo::usage="bla bla";

Begin["`Private`"]

Foo[x_]:= x^3;
SetAttributes[Foo,{Protected,ReadProtected,Locked}];

End[]
EndPackage[]

Obviously, if the user tries to load both packages on the same kernel, there will be shadowing issues. Normally one would just rename one of the functions to avoid that kind of conflicts. However, if both packages come from different developers and are encrypted/proprietary (i.e. there is no way to modify the source code) then the user seems to be out of luck.

So is there any possibility to load the two packages on the same kernel such, that the functions Foo from A and B will not go into the Global context? Then the user could use just A`Foo and B`Foo to distinguish between the two. Or are there possibly other tricks to have both functions in the same session?

$\endgroup$
  • 2
    $\begingroup$ I don't understand the question. Foo will not go in the Global` context. If you evaluate the code you posted in a newly started kernel, you'll get A`Foo and B`Foo and you can refer to them as such. You will not get Global`Foo. Simply typing Foo will refer to B`Foo because package B was loaded last and thus B` appears first in $ContextPath. $\endgroup$ – Szabolcs Mar 19 '15 at 21:52
  • $\begingroup$ @Szabolcs You're of course correct, there's nothing going into Global here. My mistake. But I'm mainly worried about the warning messages that Mathematica issues when I load both packages. Can I really ignore them (in this case) without any issues? That would mean that I can essentially do Off[General::shdw]; Needs["A"];` Needs["B"];` On[General::shdw] without any problems, right? $\endgroup$ – vsht Mar 19 '15 at 22:20
  • $\begingroup$ and with the help of $ContextPath = Select[$ContextPath, (! StringMatchQ[#, "A`" ~~ ___] && ! StringMatchQ[#, "B`" ~~ ___]) &]; I can ensure that there will be no confusion between Foo from A and B. Hmm, this seems to be much easier than I thought. $\endgroup$ – vsht Mar 19 '15 at 22:35
  • 1
    $\begingroup$ You don't need StringMatchQ. $ContextPath should simply contain "A`", not A` followed by something. If you like, just use DeleteCases[$ContextPath, "A`"|"B`"] $\endgroup$ – Szabolcs Mar 19 '15 at 22:39
  • 1
    $\begingroup$ at least related seems this question of mine and all answers to it: $\endgroup$ – Albert Retey Mar 20 '15 at 12:15
5
$\begingroup$

From the comments:

But I'm mainly worried about the warning messages that Mathematica issues when I load both packages.

If the packages are properly written, and if the symbol conflict is between two packages (and not builtins and a package function), then you can safely ignore it.

From the documentation of BeginPackage:

BeginPackage["context`"] makes context` and System` the only active contexts.

This means that when package B is loading, it should be completely unaware of the existence (or any symbol definitions from) package A. So there will be no conflict. This is not the case if there's a conflict with System` symbols, as that context is still active and visible to package B during load time.

I'm assuming that the packages follow the standard structure and don't make unusual use of $Context, $ContextPath or BeginPackage.


There's a trick you might find useful:

Block[{$ContextPath}, Needs["B`"]]

will load package B without adding it to the $ContextPath. To use functions from B, now you must refer them with their full name, including the context name. The shadowing message won't be issued because there's no shadowing anymore. There's no ambiguity when resolving symbol names typed without a context.

Aside: You might wonder why this Block works at all, here's a question about that.

$\endgroup$
  • $\begingroup$ +1 btw, you seem to have left off the link to the question about Block. $\endgroup$ – Chris Degnen Mar 19 '15 at 22:55
  • $\begingroup$ Thanks, now I feel much more comfortable working with packages that use the same names! The only thing where this probably might go wrong, is when both packages would define Global`Foo[x_]:=.... Although it's not a good practice, I've already seen some packages doing that. $\endgroup$ – vsht Mar 19 '15 at 22:59
  • $\begingroup$ @Szabolcs I also would like to see the link to the question about Block. Could you please add it? $\endgroup$ – vsht Mar 20 '15 at 17:56
  • $\begingroup$ @vsht Fixed the link, sorry about that. It's not particularly interesting, it's just good to point out that Block doesn't in fact clear $ContextPath, so this doesn't break the code within. Also not that $ContextPath affects parsing, not evaluation. Thus the code literally written inside the Block won't be affected. But the code loaded by Needs will be because it is parsed only after the $ContextPath-change has taken effect. $\endgroup$ – Szabolcs Mar 20 '15 at 18:40

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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