8
$\begingroup$

I'm writing my package (.m) in Mathematica and when I call the function it returns 0 instead of a right output.

Here's my code:

Package.m

BeginPackage[ "MyP`"]

Begin[ "`Private`"]

 MyLagrange[f_]:= Module[{a},
      a = D[f,x1];
      a
 ]

End[]

EndPackage[]

If my input is f = Log[x1] it returns 0 instead of 1/x1, what's wrong?

$\endgroup$
  • $\begingroup$ Declare Global`x1 in between BeginPackage[] and Begin[], and try again. $\endgroup$ – J. M. is away May 10 '16 at 10:13
  • 1
    $\begingroup$ @SimonRochester while linked topic is older I'd make it a duplicate of this one. It is because the answer here is more general. Sorry but your solution requires to clear the kernel, before loading a package, to avoid shadowing problems with all exported dummy symbols (here x). Not to mention that if two packages export x the shadowing will be unavoidable. $\endgroup$ – Kuba Dec 22 '16 at 10:45
  • $\begingroup$ @Kuba I am inclined to agree, but I never like closing older questions as duplicates of newer ones. That doesn't mean I won't do or allow it, it's just how I feel about it. One alternative that comes to mind is to merge these questions which would move your more general answer to the older question; this would "cost" you an Accept but it would juxtapose your method and caveats with the seemingly simpler approach shown in Simon's answer. $\endgroup$ – Mr.Wizard Dec 22 '16 at 17:13
  • 1
    $\begingroup$ @Mr.Wizard I'm fine with that, feel free to merge :) $\endgroup$ – Kuba Dec 22 '16 at 17:37
  • $\begingroup$ @Kuba I will wait 24 hours in case anyone has an objection or wishes to reopen this question as a Merge is impossible to reverse without SE developer intervention. (please remind me if I forget) $\endgroup$ – Mr.Wizard Dec 22 '16 at 17:38
11
$\begingroup$

Short explanation

It returns 0 because you are doing something like:

D[ Sin[Global`x1], MyP`Private`x1]
  (*Global` or current $Context really*)

Why? Full answer would be long so I'm sending you to topics linked below, short answer for the most frequent case is:

x1 in notebook will be created in Global` context while x1 from the package in MyP`Private`. And this will happen whether you will use x1 before <<MyP` or after. When MyLagrange[f_... is parsed, $ContextPath contains MyP` and System` only. Also, tricks with putting Global` inside the package won't work when the notebook you are working with has CellContext->Notebook.

You can read more in a related topic: Behavior of Remove inside a Package and in the general one I'm encouraging you to become familiar with: How symbol lookup actually works


Handy tip to consider

MyPackage`Private` context is used so that package implementation symbols won't interfere with outside world.

But the behavior you expect is exactly the opposite!

So if that package is only mean for you for daily research you can just delete Begin/BeginPackage/End/EndPackage and leave a script which will just load some definitions into current context. That is not a general way to go with code meant for distribution but may be just fine for you.

Otherwise read further.


Generic solution

There are some tricks available to detect a variable that we need to differentiate with respect to but I'd say the safest thing is to provide it explicitly:

ClearAll["MyP`*"];

BeginPackage["MyP`"];

   MyLagrange;

Begin["`Private`"];

   MyLagrange[f_, var_] := Module[{a}, 
      a = D[f, var];
      a
   ];

End[];
EndPackage[];

MyLagrange[Sin[x1], x1]
Cos[x1]

I don't think it is too much of a hassle since all D and Solve functions are asking you for related symbols anyway.


Hairy shortcuts

Alternatively you could go with

  • a = D[f, Symbol[$Context <> "x1"]]

    Probably the most stable from this section.

    The problem here is that you force the user to always use x1, does e.g. Solve force you to always use x?.

    Another one is that the x1 could be on $ContextPath but not in $Context. The best example is a package. After Begin["`Private`"] the $Context is MyPackage`Private` while x could have been introduced in MyPackage` earlier. That sounds artificial but still can happen and it is a straightforward way to break your code.

or

  • a = D[f, Global`x1]

    Same as above but even more restricted because the function will only be usable when $Context is Global`. Sounds useful enough? Notice that you can't change notebook's context to 'unique to this notebook' or you cant use that function inside another package.

or

  • D[f, FirstCase[Level[f, {-1}], _Symbol]]

    you never know what's inside f and maybe there are some constant symbols that should just be ignored.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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