10
$\begingroup$

I have written a package in Mathematica 11, and I would like to provide some backwards compatibility to earlier versions. An example is the function Echo.

Currently I define Echo in the following way.

Quiet[System`Echo[x_] := (Print[x]; x);]

As far as I understand, this defines Echo for example in version 10 where it was not part of the core language, and in version 11 it does nothing.

This is fine when I'm working inside of Global`, but when I go into my package's Private` I then have problems. My package seems to try to access Private`Echo when I write just Echo, but I would like it to access System`Echo.

To me this seems like it should be the default behaviour; as far as I understand other core language functions such as Print are in Sytem` and so I think Mathematica should look inside of System` before looking inside of Private`, only it appears not to.

Can anybody explain to me why this doesn't work? And any suggestions for a solution would be great, thank you.

EDIT:

Here is some example code, which all sits in my package file.

Quiet[System`Echo[x_] := (Print[x]; x);]

BeginPackage["Example`"];
myfunc::usage = "";
Begin["`Private`"];

myfunc[x_] := Echo[x^2]

End[];
EndPackage[];

I would like to be able to access Echo both inside the package, and in a session where the package is loaded. In this current example, the call to Echo in the package accesses Private`Echo, which is not what I want.

EDIT2: The above code works fine, thanks to Szalbocs for pointing out a missing backtick.

$\endgroup$
  • 2
    $\begingroup$ When do you define this Echo? Before or after you load your package? $\endgroup$ – b3m2a1 Jul 6 '18 at 2:16
  • 1
    $\begingroup$ To discuss the context where Echo is created, we would need to know what you are doing exactly (a complete minimal example, also pointing out the order of operations) $\endgroup$ – Szabolcs Jul 6 '18 at 7:39
  • $\begingroup$ That should be Begin["`Private`"] and not Begin["Private`"]. I cannot reproduce the problem you claim. $\endgroup$ – Szabolcs Jul 7 '18 at 6:27
  • 1
    $\begingroup$ Ohhhh.... I see. I'd been using Begin["Private`"] for quite a while. It works fine now, thank you very much. $\endgroup$ – Joe Jul 9 '18 at 17:23
14
$\begingroup$

If you just want backwards compatibility, there is no need to create any symbols in the System context. It seems like a bad idea to do such things. A package should create symbols only within its own context to avoid conflicts. Imagine what would happen if two different packages tried to define System`Echo, each in their own and incompatible way?


I suggest you simply do

If[$VersionNumber >= 10.3,
  echo = Echo,
  echo[x_] := (Print[x]; x)
]

in the private section of the package, then use echo. This is what I personally do.

If you insist on using Echo instead of echo, it is still not necessary to create symbols in the System context. This will work:

If[$VersionNumber < 10.3,
  Echo[x_] := (Print[x]; x)
]

In 10.2 and earlier, Echo will live in the `Private` context of the package, but that won't affect how your package functions can use it. (However, should someone else's package make the questionable decision to create System`Echo, this approach will fail.)

However, I think it is a much better idea to use a distinct name such as echo. There are several advantages:

  • You can work around bugs in earlier versions (I had to do this on several occasions)

  • You can not only add a missing function, but add missing features of a function without having to modify System context symbols.

  • You can more easily achieve consistent behaviour between versions. Your Echo implementation is not exactly equivalent to the built-in Echo. Recreating a complex built-in function is often difficult. Instead, focus on an easy-to-implement subset of functionality.

Other tips to help with backwards compatibility

  • Always, always test in the earliest version that you need to support. I learned the hard way that there will be unexpected incompatibilities.

  • Do not rely on the Updated in... line at the bottom of documentation pages. Check for yourself when the change was introduced. These version notes in the documentation are automatically generated based on when the documentation page was last changed, not based on when the function was last updated.

  • Use the Mathematica plugin for IntelliJ IDEA. It allows setting a target version and will flag any functions that you are trying to use that are not available in that version.

    enter image description here

$\endgroup$
  • $\begingroup$ Thanks for your advice. I'd like to define Echo and not echo. I avoided using $VersionNumber because that way I don't have to check what version things were added in. I want this Echo to be accessible to a session with the package loaded and not just the package internally. I don't need to add it to System` , that was just what I thought made sense. Global` didn't work for me either. I have updated my question. $\endgroup$ – Joe Jul 6 '18 at 21:37

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.