13
$\begingroup$

One can use $Epilog to do something when the Kernel is quit or put an end.m file next to the init.m.

For Wolfram System sessions, $Epilog is conventionally defined to read in a file named end.m.

But if $Epilog is set by the user, then end.m is skipped.

Question: So what to do if I want something to be done each time Kernel is quit but I also want to be able to play with $Epilog. In that sense that if I set $Epilog I would like my default action to be taken anyway?

I need to stress out that I want to establish an action that will not be accidentally overwritten with daily (but advanced) mma usage.

$\endgroup$
5
  • 1
    $\begingroup$ Hackety-hack: could you define an upvalue on SetDelayed[$Epilog,f_] such that you append the calling of your end.m to the execution of f? $\endgroup$ Commented Mar 16, 2016 at 12:21
  • $\begingroup$ @MartinBüttner it's worth considering that. I need to stress out that I wan't to establish an action on quit that will not be accidentally overwritten with daily (but advanced) mma usage. So your solution is quite stable except the fact I have to include it in init.m. $\endgroup$
    – Kuba
    Commented Mar 16, 2016 at 12:23
  • $\begingroup$ I'd post it as an answer, but thinking about it I'm actually not quite sure how I'd call the unmodified SetDelayed inside the upvalue definition (so as not to run into infinite recursion). I'm sure it's possible, but I'm not that familiar with upvalues. $\endgroup$ Commented Mar 16, 2016 at 12:30
  • 1
    $\begingroup$ mathematica.stackexchange.com/q/104403/12 I have no robust solution for cleaning up on exit and playing nice with any other software that messes with $Epilog or end.m. I gave up on this. $\endgroup$
    – Szabolcs
    Commented Mar 16, 2016 at 13:11
  • 2
    $\begingroup$ I asked about it on W Community: community.wolfram.com/groups/-/m/t/824185 $\endgroup$
    – Szabolcs
    Commented Mar 16, 2016 at 14:26

3 Answers 3

7
$\begingroup$

If you are willing to rely on undocumented behavior you can move $Epilog out of the System context, and give it a definition that evaluates both an internal (default) expression as well as the public expression assigned to System`$Epilog.

Your specialized setup:

Context[System`$Epilog] = "hidden`";
hidden`$Epilog := (Print["internal"]; System`$Epilog)

An arbitrary public definition:

$Epilog := Print["external"]

Now when the kernel is terminated:

Exit[]
internal

external
$\endgroup$
7
  • 1
    $\begingroup$ Why does it work? :) In what conditions Mathematica calls $Epilog so it is found on hidden` context first? $\endgroup$
    – Kuba
    Commented Mar 16, 2016 at 12:47
  • $\begingroup$ @Kuba hidden`$Epilog is still the internal Mathematica function and it is called by low level reference, I assume. This is no different from moving any other Symbol out of the System context and having it still function when called directly, e.g. you can move Range to foo`Range and when you use foo`Range[1, 5] it still works. $\endgroup$
    – Mr.Wizard
    Commented Mar 16, 2016 at 13:01
  • $\begingroup$ Yeah but $Epilog := Print["external"] knows you are using System` because it is on context path, why MMA doesn't know it is there too when it calls $Epilog at the end? $\endgroup$
    – Kuba
    Commented Mar 16, 2016 at 13:05
  • $\begingroup$ @Kuba I believe the reference is made at a lower level, meaning that the Kernel is not parsing and evaluating a textual input $Epilog but instead performing e.g. "operation 3F70BE" which happens to correspond to $Epilog. Contexts are a higher-level abstraction. $\endgroup$
    – Mr.Wizard
    Commented Mar 16, 2016 at 13:10
  • $\begingroup$ Doing Context[StringQ] = "myContext`" before loading the documentation center seems to break the documentation center. $\endgroup$ Commented Mar 17, 2016 at 9:05
5
$\begingroup$

In principle this can be done using LibraryLink. Just run an action on library unload. The library will be unloaded on kernel exit, if you don't unload it manually before.

Warning: This is a heavyweight solution that just won't be practical in most cases. But it does work and it does not conflict with other packages. If you need to do the cleanup privately, only on your own computer, then it can be useful. If you need to do the cleanup from a package that already uses LibraryLink, then it is useful. Otherwise I wouldn't use it.

For reasons of laziness, here's with LTemplate:

<< LTemplate`

tem = LClass["Cleanup", {}];

SetDirectory[$TemporaryDirectory];
code = "
  struct Cleanup {
    ~Cleanup() { 
        mma::print(\"C++: Cleaning up\"); 

        // this below calls myCleanupFunction[]
        MLINK link = mma::libData->getMathLink(mma::libData);
        MLPutFunction(link, \"EvaluatePacket\", 1);
            MLPutFunction(link, \"myCleanupFunction\", 0);
        mma::libData->processMathLink(link);
        MLNextPacket(link);
        MLNewPacket(link);
    }
  };
  ";
Export["Cleanup.h", code, "String"];

CompileTemplate[tem, "ShellOutputFunction" -> Print]

LoadTemplate[tem]

This will be called on exit:

myCleanupFunction[] := Print["Mathematica: Cleaning up"]

We create a special object. When this object is no longer referenced, or when the library is unloaded, the cleanup code will be run.

globalCleaner = Make["Cleanup"] 

(* Cleanup[1] *)

Now we quit:

Quit

Quitting triggers unloading the library and this gets printed:

C++: Cleaning up

Mathematica: Cleaning up

Standard LibraryLink is a bit different than LTemplate. You'll need to put the code form the destructor above into WolframLibrary_uninitialize() and there's no need a create a special object like Cleanup[1]. I have not tested it (again: laziness), but I expect it will work the same way.

$\endgroup$
1
$\begingroup$

Add the default epilog code to your own. This is what the default does.

?? $Epilog
$Epilog:=If[FindFile[end`]=!=$Failed,<<end`]
$\endgroup$
1
  • $\begingroup$ The point is, I want to set an action in end.m or any other way and I don't want to care about that. Using composition each time is not an option, unless we use a trick suggested by Martin in the comment. $\endgroup$
    – Kuba
    Commented Mar 16, 2016 at 12:26

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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