I have some Mathematica code that shows a behaviour I really cannot understand.
The code only contains a bunch of function definitions. If I paste it in the Notebook Front End and I evaluate it, I can then use those functions and they work as expected. Until here everything's fine.
The problems start when I try to create a Package with the same code.
I exported the code from the Notebook to a Package and I saved to a file.m
file.
When I load the package with the command Get["path/to/file.m"]
, it is loaded correctly and the functions defined in the package become visible in the new Notebook where I loaded the package.
The problem is that some functions (at the moment just one foo
) do not return the same results on evaluation if they are loaded from the package as if they were simply copy-pasted into the notebook.
I have read around several threads here on stack exchange, on the Wolfram forum and in the documentation and I have already checked the following things in my code:
I know that when packages are loaded with
Get[]
only the initialization cell is evaluated. My Package is composed only by a single cell, which is also marked as Initialization Cell.I know that Input Cells are discarded in Packages and only Code Cells are evaluated. The only cell in my Package is Code.
I know about
$Context
and$ContextPath
and that some variables and functions defined in the Package can shadow globals. I am not sure I completely understood all the nuances of these concepts but I placed the function definitions in the private block of the package. UPDATE: I was able to reduce the example to avoid variables, so this should not represent a problem anymore.I also double-checked that the kernel was fresh in both cases:
- when I executed the code directly from the Notebook
- when I loaded the newly created package with the same code
After some work I managed to shrink the original Notebook to a minimal subset that reproduces the odd behaviour.
Here is the updated and reduced Notebook:
NaN=Indeterminate;
floatQ[x_]:=If[NumericQ[x],
If[Head[x]=!=Complex,
True,
False
],
If[x===∞∨x===-∞∨x===NaN,
True,
False
]
]
bar[x_/;floatQ[x]∧x!=∞∧x=!=NaN]:=If[x==0,
0,
⌊Log[2,Abs[x]]⌋
]
foo[x_/;floatQ[x]∧x!=∞∧x=!=NaN]:=If[x==0∨bar[x]==1,
1,
⌈Log[2,1+Abs[bar[x]-1]]⌉+1
]
If I evaluate it and then run following commands I get the following result which is correct.
The code for the package instead is the following:
BeginPackage["minimal`"]
bar::usage = "bar[float_number]"
foo::usage = "foo[float_number]"
Begin["`Private`"]
NaN=Indeterminate;
floatQ[x_]:=If[NumericQ[x],
If[Head[x]=!=Complex,
True,
False
],
If[x===∞∨x===-∞∨x===NaN,
True,
False
]
]
bar[x_/;floatQ[x]∧x!=∞∧x=!=NaN]:=If[x==0,
0,
⌊Log[2,Abs[x]]⌋
]
foo[x_/;floatQ[x]∧x!=∞∧x=!=NaN]:=If[x==0∨bar[x]==1,
1,
⌈Log[2,1+Abs[bar[x]-1]]⌉+1
]
End[]
EndPackage[]
If I close Mathematica and reopen it (so that I am sure I have a fresh Kernel), and I try to Get[]
the package and run the same commands as above I get the following wrong result.
What am I doing wrong?
UPDATE This is not true anymore. I have worked on the example and I have been able to reduce it further as the code above shows. Now there are no variable definitions, just some simple functions that I wrote myself.
Unfortunately the minimal example is not so minimal, but I didn't write the original code myself. It comes from a Notebook I got from the internet and I have not been able to reduce it further. I also tried with some code I wrote, but I have not been able to obtain the same misbehaviour.
As you can see the code in the Notebook and in the Package are really the same, except for the BeginPackage[]
EndPackage[]
portions.