# How to limit number of user-defined messages issued per evaluation

I have written code such that if it runs into a particular function, a warning message is issued. However, it is common for the program to call this function several times in a single evaluation, but the warning message need be issued only once.

How do you limit the number of times a message is issued per evaluation?

Here is an example:

 Clear[badness];
ClearAll[badness];
badness::oops = "Watch out!  Result could be misinterpreted.";
badness[0] := CompoundExpression[Message[badness::oops]; 0]

Clear[reduction]
f[0] = 0;
reduction = {f[x_] :> x + f[x - 1] + badness[0]};


So, If the user runs the following:

 f[5] //. reduction


we get:

Is there a way to limit the number of times (without also getting the General::stop) the message badness:oops is given to the user? (In the particular case for my code, I would like to limit it to just one time.)

• Good question...I would have expected that CurrentValue[$FrontEndSession, {MessageOptions, "MaxMessageCount"}] = 1; or SetOptions[$FrontEndSession, {MessageOptions -> {"MaxMessageCount" -> 1}}] would the job , but it doesn't -- you still get 3 messages before General::stop kicks in :( -- Version 9.0.1.0 Windows 8 64bit). – kglr Aug 24 '14 at 18:51
• Closely related: (2459) – Mr.Wizard Aug 27 '14 at 5:22

## 3 Answers

It's been a day and no has posted a truly elegant, natural, and general solution, so I'll post a narrow one.

By default, a message is stopped when it occurs three times in $MessageList. One can reduce the number of times a message is printed by pre-loading $MessageList with it.

Block[{$MessageList}, Unprotect[$MessageList];
$MessageList = {HoldForm[badness::oops], HoldForm[badness::oops]}; f[5] //. reduction ]  badness::oops: Watch out! Result could be misinterpreted. General::stop: Further output of badness::oops will be suppressed during this calculation. >> (* 15 *)  To have it happen automatically every time, use $Pre:

SetAttributes[foo, HoldAll];
foo[new_] := Block[{$MessageList}, Unprotect[$MessageList];
$MessageList = {HoldForm[badness::oops], HoldForm[badness::oops]}; new]$Pre = foo;


Or one could put the code in a function:

ClearAll[almostOff];
SetAttributes[almostOff, HoldAll];
almostOff[code_, msgs__] := Block[{$MessageList}, Unprotect[$MessageList]; $MessageList = List @@ HoldForm /@ Hold[msgs, msgs]; code ] almostOff[f[5] //. reduction, badness::oops]  • Warning: messing with$MessageList might break unit testing tools that can test messages. – Szabolcs Sep 13 '15 at 11:26

Here is a method using Off and On triggered by the first appearance of the message.

• I avoid unprotecting any System Symbols by using TagSetDelayed.

• I use $Post to turn the message back on. • Modification of your function is not required; this operates via the low-level Message system. Code: badness::oops = "Watch out! Result could be misinterpreted."; badness /: p : MessagePacket[badness, "oops", _BoxData] /; msgLimit =!= True := Block[{msgLimit = True}, Off[badness::oops]; p]$Post = (On[badness::oops]; #) &;


Now:

badness[0] := (Message[badness::oops]; 0)

f[5] //. {f[0] :> 0, f[x_] :> x + f[x - 1] + badness[0]}


badness::oops: Watch out! Result could be misinterpreted.

15


And again:

f[5] //. {f[0] :> 0, f[x_] :> x + f[x - 1] + badness[0]}


badness::oops: Watch out! Result could be misinterpreted.

15


This is a bit ugly, but it seems to do what you want.

ClearAll[badness];
badness::oops = "Watch out!  Result could be misinterpreted.";
badness[0] /; badness[] := (Message[badness::oops]; badness[] = False; 0);
badness[_] := 0

Clear[reduction]
f[0] = 0;
badness[] = True;
reduction = {f[x_] :> x + f[x - 1] + badness[0]};


All it does it keep track of whether it has shown the message or not. If badness[] is True it shows the message and sets badness[] = False. This could easily be adapted to keep a count. The major drawback is that you have to manually set badness[] = True to show the message again.