4
$\begingroup$

There is a similar question about this, 8 years ago!, but the answer there does not really give what to do. The answer just says yes one can use same function name in different packages but has use the contexts correctly to do that. Ok, But how?

symbol-appears-in-multiple-contexts-when-load-two-packages-with-unique-function

Adding comment there now for clarification, is not too useful and will not likely be seen. So I am posting this question again asking for a possible direct simple solution to this problem from the package experts.

I searched for last 2 hrs and read many posts and I see no one giving simple solution other one I found and will show it below, but I am not sure if this what I should do or not as I am not too familiar with writing packages.

Here is the problem again. I want to have 2 packages a and b both below same context name nma. So there will be

nma`a`
nma`b`

packages. These are loaded from the notebook using the command

<<nma`

The problem is that each package a and b has public function called foo. And this causes the problem. I set up the package layout as described in many posts, under $BaseDirectory/Applications using this layout

          Application/
            nma/
              Kernel/init.m
              a.m
              b.m

Where init.m is

<<nma`a`
<<nma`b`

And a.m is

BeginPackage["nma`a`"] 
Unprotect @@ Names["nma`a`*"]; 
ClearAll @@ Names["nma`a`*"]; 
 
foo::usage = "foo[x]" 
Begin["`Private`"]      
foo[x_] := Module[{}, x^3];      
End[]; 
Protect @@ Names["nma`a`*"]; 
EndPackage[];

and b.m is

BeginPackage["nma`b`"] 
Unprotect @@ Names["nma`b`*"]; 
ClearAll @@ Names["nma`b`*"]; 
 
foo::usage = "foo[x]" 
Begin["`Private`"]      
foo[x_] := Module[{}, x^2];      
End[]; 
Protect @@ Names["nma`b`*"]; 
EndPackage[];

Now when doing, from notebook

Mathematica graphics

One solution I saw (which I lost the link to now, but will try to find it) says to solve this problem is to change init.m to the following

<<nma`a`
$ContextPath = Rest@$ContextPath;
<<nma`b`

And now doing

<<nma`

no longer produce this warning.

my question is, is this the correct way to solve this? Should one then insert $ContextPath = Rest@$ContextPath; between each package they load in init.m? Like this:

<<nma`a`
$ContextPath = Rest@$ContextPath;
<<nma`b`
$ContextPath = Rest@$ContextPath;
<<nma`c`
$ContextPath = Rest@$ContextPath;
<<nma`d`
$ContextPath = Rest@$ContextPath;
<<nma`e`

I wanted to make sure about this and if there is a better way to handle this. It is strange that same function name but in two different packages should clash with each others like this.

I put the whole nma tree above in one zip file if it helps. Here is the zip file.

$\endgroup$
1
  • 1
    $\begingroup$ Thanks for both great answers. I wish I can accept both. $\endgroup$
    – Nasser
    Oct 3, 2022 at 0:22

2 Answers 2

5
$\begingroup$

I am often annoyed by the shadowing message, because it ends up being issued when you don't ever have the two symbols on the context path at the same time but in this case I think the message is correct and usually helpful.

If you do not want all of the symbols in nma`a` available on the context path then you should not call Get on it. To read in a file that declares a package without also adding those symbols to your context path use something like

getFile[file_]:=Internal`InheritedBlock[{$ContextPath},Get[file]]
getFile["nma`a`"]
getFile["nma`b`"]

With the above in your init.m file I can call

<< nma`

without message, and I can call either nma`a`foo or nma`b`foo without error so long as I use their full name.

$\endgroup$
4
$\begingroup$

The answer will depend on the desired behavior. I see two options:

  • One can ignore the warning message. This makes sense for people who understand that shadowing occurs and understand that full names need to be used to access shadowed public symbols, but still want the convenience of accessing non-shadowed public symbols via their short names. To more conveniently access shadowed symbols, one can introduce shorthands such as fooA = packageA`foo, or use $ContextAliases.

  • One can remove packages manually from $ContextPath, as OP suggests. To understand the purpose of this, see the documentation of EndPackage. The thing to be aware of in this case is that for a package removed from $ContextPath, no public symbol can be accessed via its short name. On the upside, this approach removes the danger of unintentionally getting the wrong symbol.

In either case, the warning message can be turned off using, for example, Off[General::shdw].

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