1
$\begingroup$

I have a .wl package and a demo .nb notebook. The package file is testPackage.wl and it consists of:

BeginPackage["testPackage`"]

testIntegrator::usage = 
"Demonstrates an issue with Context in my package"


Begin["`Private`"]

testIntegrator[ v_]:=
Module[
    {vSub,odes,vp},
    vSub=(v/.{x->x[t]});
    odes={
    x'[t]==vSub,
    x[0]==x0
    };
    vp=x[t]/.ParametricNDSolve[
    odes,
    x[t],
    {t,0,1},
    {x0}];
    vp
]


End[]

EndPackage[]

The notebook that runs this code is demos.nb and it consists of

<< testPackage.wl
pf = testIntegrator[Exp[-x]]
Plot[pf[.1], {t, 0, 1}]

When I run the above notebook, it returns a non-usable ParametricFunction object, which appears to be due to issues with the context of the dependent variables. The function looks like this

enter image description here

In comparison, if I define the function in the notebook itself (rather than in an external .wl file), I do not have this problem. The function correctly returns this output

enter image description here

How do I correctly handle the variable contexts when defining functions in an external package? I think that my variable substitution (v/.{x->x[t]}) likely may be at fault, but I am unsure how to modify it.

$\endgroup$
1
  • $\begingroup$ I think the linked topic should answer all your doubts. Let me know if you disagree with marking it as a duplicate. $\endgroup$
    – Kuba
    May 6, 2019 at 8:27

1 Answer 1

3
$\begingroup$

I'd say the best solution is to re-design the function as

testIntegrator[v_, x_, t_]:= …

But if you insist on the original design, which is undoubtedly a bad design, then place a line x;t; before Begin["`Private`"] i.e.

…
x; t;
Begin["`Private`"]
…

Don't forget to restart the kernel or Remove[Global`x, Global`t] first.

BTW, if you just don't care about context, simply removing all the BeginPackage, Begin, End, EndPackage is also a possible solution.

You may check the following post for more information:

Creating Mathematica packages

$\endgroup$
3
  • $\begingroup$ Thank you, I am new to best practices package design. Would you mind clarifying why the original design is bad? Is the idea that I should always make sure that all values at which the function is evaluated are explicit arguments? Or is using NDSolve within a function like this inherently a bad approach? $\endgroup$
    – wil3
    May 5, 2019 at 23:52
  • $\begingroup$ @wil3 The design is bad because, x and t are both frequently used variables, but your package monopolize them. “Is the idea that I should always make sure that all values at which the function is evaluated are explicit arguments? ” Not always. Another possible design is to make the variable unique enough. (Remember those system variables start with $? ) $\endgroup$
    – xzczd
    May 6, 2019 at 5:34
  • $\begingroup$ @wil3 have you read the topic I linked below your question? $\endgroup$
    – Kuba
    May 6, 2019 at 7:10

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