12

I'm trying to find a shortcut to the following loop. When developing a mathematica's package one is implementing changes to the .m file's code and then want to test the changes in another notebook. This is an infinite loop...

So, we have a package package.m and a notebook test_package.nb where testing is done. Currently, when ever I change something in the .m file, I then have to:

Quit[]
Needs["package`"]

in the notebook for the changes to become available, so I can test them. It seems like without the Quit[] it doesn't work.

Is there a shorter way to iterate this development loop? In particular avoid the quitting?

Aftermath

If I could, I'd accept both ruebenko and Leonid's answers as both are helpful and solve my problem. However, as only one answer can be chosen, I picked ruebenko's due to is simplicity and easiness - by simply changing the Needs to Get I overcame my problem. Nevertheless, Leonid's package is for sure more sophisticated and probably at the end of the day yields better results, but it has to be installed, loaded etc.

Michael Currie
  • 13,721
  • 9
  • 42
  • 58
Dror
  • 12,174
  • 21
  • 90
  • 160

3 Answers3

8

Use Get; Need only loads the package if is not loaded at all. Sometimes you need to be careful and use ClearAll on the variables in the package.

  • @ruebenjo: can you please elaborate on the `ClearAll` issue? Should it be in the notebook or in the `.m` file? – Dror Dec 09 '11 at 09:37
  • 1
    In the .m file. Say you edit a function that changes it's signature, if Get the file the old definition is still in the kernel. To avoid that use ClearAll[myFunction];myFunction[blab_,blah_,blah_]:=... –  Dec 09 '11 at 09:55
8

As an alternative to using simple Get, as sugested by @ruebenko (which is a good advice), you can try using a package I wrote called PackageManipulations`, which does what you want. It is available here. There is a notebook with examples illustrating how it works, also availabe at the page I linked. The package can reload, clear or remove a given package (context). The function PackageReload specifically will do what you want.

It does use Get or Needs under the hood, but in addition it will track the so-called "escaping symbols" (symbols which are publicly exported but have no usage messages, and may be "leaking" the implementation details), and optionally can resolve the shadowing problems in favor of the package being re-loaded. Note that PackageReload will automatically call Unprotect and ClearAll on package's symbols, therefore addressing the issue mentioned by @ruebenko. You can find more details in the example notebook which comes with the package.

Note that, while I used it myself many times, I don't claim it is bug-free :)

Leonid Shifrin
  • 22,449
  • 4
  • 68
  • 100
  • Time to look closer at your 'Additional Resources' ;-) – nilo de roock Dec 09 '11 at 11:19
  • 1
    @nilo de roock Unfortunately, that section has been the same for about *3 years* now (this is really pathetic). I have a lot more that I would like to add there, but so far didn't have enough time to properly package, polish and test. Hopefully, I will update that stuff soon enough. – Leonid Shifrin Dec 09 '11 at 11:41
  • @LeonidShifrin: Thanks for the addition. I tried to add it to my package's beginning (after `Unprotect@@Names["curveAnalysis`*"]; ClearAll@@Names["curveAnalysis`*"];` and before the first `usage`). In the test notebook I reverted to `Needs`. Then I tried to reload the package after changing it (without using `Quit[]`), but the changes didn't apply. I had to either use `Quit[]` or reuse the `Get` alternative. – Dror Dec 12 '11 at 08:24
  • @Dror The code I posted should work - I specifically added the test code above and tested it myself. I did not mention it, since I thought this was clear from the context, but with this addition you *must* use `Get` in any case. `Needs` does not reload the package once it has been loaded. In fact, as I already mentioned also, the function `PackageReload` from my ``PackageManipulations` `` does all this work for you automatically, including choosing which one to call (`Needs` or `Get`), calling `Unprotect` and `ClearAll` on all package names (incuding sub-contexts), and a few other things. – Leonid Shifrin Dec 12 '11 at 08:36
  • @LeonidShifrin: I'm afraid it wasn't that clear to me. Any way it works now. See my addition to the question for further details. – Dror Dec 12 '11 at 09:35
  • @Dror Well, I'll try to be more clear next time. Keep in mind that just calling `Get` will not solve your problem - you will still have to call some code similar to what I proposed in the edit, at the start of your package, to make it robust (this is what @ruebenko warned about in his answer). – Leonid Shifrin Dec 12 '11 at 09:46
1

The easiest method is to use Clear or, better yet, ClearAll on the exposed symbols in your package at the very beginning of your package, as follows

BeginPackage["SomePackage`"];
ClearAll[ ASymbol, AnotherSymbol, ...];

This ensures that you have a clean slate whenever you load it. This is easier once the package is more stable, but I find if I don't do this when I'm initially developing a package, it doesn't get done.

rcollyer
  • 10,475
  • 4
  • 48
  • 75
  • 1
    I added (as I saw it in some example) `Unprotect@@Names["package`*"]; ClearAll@@Names["package`*"];` at the beginning of my package. Is this equivalent and addresses the same problem? – Dror Dec 09 '11 at 19:25
  • 2
    @rcollyer This would be a perfect solution if either packages would not evolve or the package writer would be very disciplined (I wasn't). I was doing this as well for a while, but almost every time I got some new functions added and forgot to add them to `ClearAll`. When I got tired of nasty bugs resulting from older definitions staying with the new ones for those functions, I wrote the package I mentioned in my answer. And I have been happy (regarding this issue) ever since :) – Leonid Shifrin Dec 09 '11 at 21:40
  • @LeonidShifrin, I did say it was the easiest to implement, I did not say it was a robust solution. But, what about Dror's variant? Wouldn't that work? – rcollyer Dec 10 '11 at 02:03
  • @rcollyer It would not be the whole story because it would only clear the symbols in the main context. One would also need to call `ClearAll` on all sub-contexts (usually, this is just ``Private` ``). With this correction, it would probably work. This is pretty much what my package does, but it does all that automatically, and has some additional functionality. – Leonid Shifrin Dec 10 '11 at 09:46
  • @LeonidShifrin: Can you please write the explicit code that you think I should add in order to have my approach robuster? Thanks. – Dror Dec 10 '11 at 10:03
  • @Dror I added some code and example of use, please see my edit – Leonid Shifrin Dec 10 '11 at 10:28