Search code examples
wolfram-mathematicamathlink

Changing behavior of General::stop and the main loop


On the Documentation page for General::stop we read:

This message is generated after the indicated message has been generated for the third time in a single evaluation.

Messages are suppressed to prevent redundant or repetitive messages in long calculations.

My problem is that when working through MathLink I pass every point as a single evaluation and so General::stop never appears.

For example, if I define:

link = LinkLaunch[First[$CommandLine] <> " -mathlink"]
f[z_?NumericQ] := (Print@LinkRead[link]; 
   LinkWrite[link, 
    Unevaluated[
     EnterExpressionPacket[NIntegrate[Sin[1/x], {x, .001, z}]]]]; 
   While[Head[packet = LinkRead[link]] =!= OutputNamePacket, 
    Print[packet]]; First@LinkRead[link]);
Plot[f[z], {z, 1, 10}, PlotPoints -> 6, MaxRecursion -> 0]

I get as many Message packets as many evaluations of f[z]. Of course I would like message generarion to be stopped in the slave kernel by General::stop after generating the same message 3 times. Is there a way to achieve this?

On the documentation page for $MessageList we read that

With the standard Mathematica main loop, $MessageList is reset to {} when the processing of a particular input line is complete.

And on the page tutorial/Messages we read:

In every computation you do, Mathematica maintains a list $MessageList of all the messages that are produced. In a standard Mathematica session, this list is cleared after each line of output is generated.

May be this is a reason why General::stop does not appear? If it is true is there a way to control this aspect of the Main Loop? Is there a way to create such a non-standard Mathematica session?

EDIT: It seems that my supposition was right. If we will clear $MessageList after every Message, then General::stop never appears:

Unprotect[$MessageList]
Do[$MessageList = {}; 1/0, {10}]

So the question remains: how to disable automatic clearing $MessageList after generating output?


Solution

  • I have found the solution. It exploites again elegant hack by Todd Gayley. Here it is (of course, it must be evaluated in the slave kernel):

    $globalMessageList = {};
    Unprotect[Message];
    Message[args___] := 
      Block[{$inMsg = True, $MessageList = $globalMessageList},
        Message[args];
        $globalMessageList = $MessageList;
        ] /; ! TrueQ[$inMsg];
    Protect[Message];
    

    One can fully emulate standard behavior of Messages in the slave kernel by checking the current value of $Line and comparing it with previous value:

    If[TrueQ[$Line > lastLine], 
     LinkWrite[$kern, 
      Unevaluated[ExpressionPacket[$globalMessageList = {};]]]; 
     LinkRead[$kern]]; lastLine = $Line;
    

    :)