The more I study, the less I understand.
This is the HelloWorld package:
BeginPackage["HelloWorld`"];
helloWorld::usage="helloWorld !";
Begin["`Private`"];
helloWorld[arg_]:=arg+1;
End[];
EndPackage[];
This code works as obviously intended
(* code 1 *)
With[
{packageFile=FileNameJoin[{NotebookDirectory[],"HelloWorld.m"}]},
Needs["HelloWorld`",packageFile];
];
Print @ helloWorld[1];
Quit[];
On the contrary, this one
(* code 2 *)
With[
{packageFile=FileNameJoin[{NotebookDirectory[],"HelloWorld.m"}]},
Needs["HelloWorld`",packageFile];
Print @ helloWorld[1];
];
Quit[];
generates a message:
helloWorld::shdw: "Symbol ("helloWorld") appears in multiple contexts ({"HelloWorld`", "Global`"}); "
Now, my (bad !) reasoning is: In (* code 1 *), Needs performs its role, at a later time the helloWorld symbol is "publicly visible" (from inside the Global context), and when the function is called there are no motives to create, wherever, a new one named "helloWorld". In (* code 2 *), the same should happens; all in all the $Context inside and outside While[] is the same, as seen by
$Context
With[{a = 1}, Print @ $Context]
Quoting Mathematica's Help:
Conflicts can occur not only between symbols in different packages, but also between symbols in packages and symbols that you introduce directly in your Mathematica session.If you define a symbol in your current context, then this symbol may become shadowed by another symbol with the same short name in packages that you read in.
The point is: in (* code 2 *) I haven't defined a new helloWorld symbol, only invoked an existing and visible one.
In How to load a package without naming conflicts? is explained:
... in this way, you don't have to do anything afterwards, since, once the scope of
Blockis left, the `$ContextPath automatically is reset to its previous value.
But I can't understand how this consideration 'overwrites' the above mentioned one about $Context.
With, in your case), all the code inside is parsed as a whole, and so in your second case you create a global symbol at the parsing stage, even before your package gets loaded - and so you get the shadowing. See this discussion for a similar issue. – Leonid Shifrin Apr 17 '16 at 14:34(* code 1*)and(* code 2 *)work the same ? – mitochondrial Apr 17 '16 at 14:53Withand everything inside it is a single expression, and so should be parsed entirely before execution. It may however be not the case if e.g. the package parser works differently. I don't have the time to test now, but it isn't hard. – Leonid Shifrin Apr 17 '16 at 15:07(* code 1*)and(* code 2*)both give2– mitochondrial Apr 17 '16 at 16:54