# Function defined in a package behaves differently from when defined in a notebook

On a Windows system I'm using the Rubi rule-based integration package by Albert Rich which defines function "Int" in addition to Mathematica's Integrate. In my ..\ProgramData\kernel\init.m I have:

DeclarePackage["Rubi",{"Int"}]


which sets up automatic loading of the package when Int is used. This works fine. Furthermore I have defined a little function "Pr" which prints a HoldForm of an expression, then "=", and then the evaluated form:

Pr[x_] := Print[HoldForm[x] /. Int -> Integrate, " = ", x]
SetAttributes[Pr, HoldFirst]


Note that in the HoldForm it replaces Int by Integrate everywhere, because I want to obtain the representation with an integral sign instead of "Int[…]". This function, too, works fine, if I evaluate it inside of a Notebook and then use it there. All Ints are replaced and I get the desired result.

Now I have in ..\users..\AppData\Roaming\kernel\init.m

DeclarePackage["PrettyPrint",{"Pr"}]


and in ..\applications a file PrettyPrint.m defining function "Pr":

BeginPackage["PrettyPrint"]
Pr::usage="Pretty output"

Begin["Private"]
Pr[x_]:=Print[HoldForm[x] /. Int -> Integrate," = ",x]
SetAttributes[Pr,HoldFirst]
End[]

EndPackage[]


All this almost works fine, too. On using "Pr", the package is loaded correctly and Pr works normally. The only problem is that the Ints are not replaced. If I try some other replacement, e.g. Integrate -> D, this works fine with automatic loading of Pr. But loaded automatically, the replacement Int -> Integrate is not being done. As soon as I re-evaluate the function definition of Pr in the notebook, it works.

I'm fairly new to Mathematica, and I have tried out everything I could think of to eliminate the problem. Even if I definitely load Rubi automatically before I load Pr automatically, the problem remains. Even if I replace automatic loading of both Rubi and Pr by static "Get" commands in the respective init.m files, the problem remains.

What's the source of the problem and what's the solution? Thanks for help!

• – Kuba Sep 1 '18 at 11:49

# How to fix it.

Try to start the declaration of the package with

BeginPackage["PrettyPrint", {"Rubi"}]


This makes the symbols in the context "Rubi" public to the context "PrettyPrint": The context "Rubi" is appended to $ContextPath, the list of contexts in which Mathematica will look up symbols. # Why it does not work otherwise. If a symbol is neither found in the contexts in $ContextPath nor in $Context, a new symbol is created in $Context.

When defining your package without "Rubi" in $ContextPath, the new symbol Int will be created in "PrettyPrint", actually becoming the symbol PrettyPrintInt. Calling Pr from your working notebook whose context is usually "Global", Pr[Int[...]] will be interpreted as Pr[RubiInt[...]] because "Rubi" is in the $ContextPath of "Global" (since you used Get or Needs to load "Rubi"; this also appends "Rubi" to \$ContextPath. So, next thing to evaluate is of the form

RubiInt[...] /. PrettyPrintInt -> SystemIntegrate


Now it is obvious why no replacement happens.

# The hacky way.

You could also refer directly to the full name RubiInt in the definition of Pr`, but that's not supposed to be a good way. Think of many, many functions in many different packages have to be maintained, and at some point, your lead developer decides to rename one of the packages. That would break all your code.

• Thanks a lot, this works and I understand your explanation. One thing: Stack exchange did not let me edit your first line of code: } and " have to be switched around, I suppose. – Roland Salz Aug 31 '18 at 22:49
• Fixed it. Thanks for the notice! And of course, you're welcome! – Henrik Schumacher Aug 31 '18 at 22:50