9

I am using a package that was written for Mathematica 3 while I am now working on Mathematica 8. I have issues with 2 functions in particular, Order and GraphComplement. They are a part of this package but are also present in Mathematica 8 by default but with distinctly different arguments and working. (I am assuming they weren't around in Mathematica 3)

Now when I make use of some other functions in this package they make calls to both Order and GraphComplement and it keeps trying to use the in built wolfram version. I instead want it to use the one that comes with the package.

Can anyone point me to the right direction?

Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • How hard would it be to edit the package file and do a search and replace? (just curious how large a package it is) – Jason B. Jan 07 '16 at 07:57
  • Or basically overwrite all existing functions whenever an external one is imported with the same name? – jasonheush12 Jan 07 '16 at 08:38

1 Answers1

9

If I understand the problem I think I can help, but what I propose is a bit weird. I think you have a package that uses the unqualified Symbol name Order internally, and you need the package not to see the System`Order Symbol while it is defined. To effect this you can temporarily change the Context of Order, then put it back after loading the package.

As an example here is a bare-bones package defining a function foo that uses an internal definition for Order:

BeginPackage["MyStuff`"]

foo::usage = "my function";

Begin["`Private`"]

Order[args___] := {args} === Sort[{args}];

foo[a_, b_] := If[Order[a, b], "Arguments are in order", "Arguments are out of order"]

End[]

EndPackage[]

After saving this to foo.m if I call Get[foo.m] and try to use foo I have a problem:

Get["foo.m"]

foo[1, 2]

SetDelayed::write: Tag Order in Order[args___] is Protected. >>

If[1, "Arguments are in order", "Arguments are out of order"]

But if, after restarting the kernel, I first move Order out of the System context before loading the package:

Context[System`Order] = "hold`";

Get["foo.m"]

Context[hold`Order] = "System`";

I can now call my foo as intended:

foo[1, 2]
foo[4, 2]
"Arguments are in order"

"Arguments are out of order"

This works because while the package is being defined Order is not found in the context path, and a new Symbol MyStuff`Private`Order is created and defined instead:

Definition[foo]
foo[MyStuff`Private`a_, MyStuff`Private`b_] := 
 If[MyStuff`Private`Order[MyStuff`Private`a, MyStuff`Private`b],
   "Arguments are in order",
   "Arguments are out of order"]

And Order still works elsewhere as its context is restored:

Order["a", "b"]
1
Mr.Wizard
  • 271,378
  • 34
  • 587
  • 1,371
  • This is... exactly what I was looking for. It seems to work flawlessly for Order however when I try to do this for GraphComplement I get this:

    SystemGraphComplement::shdw: Symbol GraphComplement appears in multiple contexts {System,GrafPackBasics}; definitions in context System` may shadow or be shadowed by other definitions. >>

    Any idea what went wrong here?

    – jasonheush12 Jan 07 '16 at 10:16
  • Just checked. The warning is there but it seems to work fine anyway. Much thanks my friend. Accepted. :) – jasonheush12 Jan 07 '16 at 10:31
  • @jasonheush12 Thanks for the Accept. Don't hesitate to remove it if you find this fails. Your warning is probably caused by a background (re)load of GraphComplement. Try using that System function in some trivial application before changing its context and loading your package, and see if the message goes away. (Incidentally I ran into these background load consequences myself here.) – Mr.Wizard Jan 07 '16 at 10:57
  • 1
    +1, Nice use of this change-symbol-context capability. However, I personally still view this as a hack (although probably the best one can do). The real way out would be to implement an alternative loader (Get / Needs) with a read stage (access to code in box form, and then fully parsed but not yet evaluated, using hooks to inject user-defined operations). In this way, we might for example get a code in held form, already parsed, and then simply replace all System`Order symbols to MyPackage`Order. – Leonid Shifrin Jan 07 '16 at 15:25
  • @Leonid That sounds like a more robust approach, but I'm far too lazy. :^) Oh, and thank you. – Mr.Wizard Jan 07 '16 at 15:39
  • @Mr.Wizard The real problem is, this (new loader) can't be successful as a small stand-alone piece. It has to come together with a new package / module system, that would be 1. Compatible with the existing one 2. Extensible and having more possibilities. I did some work on such things, and a few experiments, but didn't have the time to make something robust and self-contained. I plan to return to this topic at some point, there are several reasons why such thing can be very useful (another one would be real read time and a possibility for Lisp - style macros). – Leonid Shifrin Jan 07 '16 at 15:50