So I have a little bit more info, but mostly a learning technique we can test:
Init
I wanted to see when each of these was called so I made each possible handler (without a previous assignment) just call Print
. Then I found that for "Wolfram.System.Print"
this is a terrible idea as it is called anytime the system prints. So I removed that. Here's what I'm working off of:
With[{h = #},
Internal`AddHandler[h, Print@(h -> {##}) &]
] & /@
DeleteCases[Keys@Internal`Handlers[],
"VetoableValueChange" | "Wolfram.System.Print" | "ValueChange" |
"Message"
];
Message
"Message"
works just as described by Szabolcs. Each time a possible message is generated Hold[mspec_Message, onQ]
gets passed to your handlers.
MessageTextFilter
"MessageTextFilter"
seems to be applied whenever Message
is called (as best I can tell) which means it doesn't get applied for quieted messages. It takes the sequence template_String,Hold[mn_MessageName],Hold[mcall_Message]
as its arguments.
If it returns a string, this is passed as the message text. For example:
ignoreSet[_, _, Hold[Message[Set::nosym, _]]] :=
"Well this is fun";
Internal`AddHandler["MessageTextFilter",
ignoreSet
]
_ = 1
Set::nosym: Well this is fun
NewSymbol
"NewSymbol"
works pretty much just as $NewSymbol
does. Everytime a symbol is added to Mathematica's symbol table the handlers get called, being passed {symName_String,context_String}
.
RemoveSymbol
"RemoveSymbol"
is the exact opposite. Everytime a symbol is removed from that table (I've only gotten this to happen with Remove
) the same list gets passed to the handlers.
ValueChange
"ValueChange"
can be very useful.
I set it like so:
Internal`AddHandler["ValueChange", (Print["ValueChange" -> {##}] &)];
The symbol in question needs to be tracked internally for it to work, though. I.e. Internal`TrackExpression
or Internal`SetValueTrackExtra
needs to have been called on it so that it's in Internal`GetTrackedSymbols[]
.
It seems to remove the symbol from Internal`GetTrackedSymbols[]
after a single call.
The change cases I've seen look like:
Internal`TrackExpression[b, 1];
Clear[b]
ValueChange->{HoldComplete[b,Clear]}
Internal`TrackExpression[b, 1];
Block[{b}, b]
ValueChange->{HoldComplete[b,Block,True]}
ValueChange->{HoldComplete[b,Block,False]}
1
Internal`TrackExpression[b, 1];
Block[{b = 1}, b]
ValueChange->{HoldComplete[b,Block,True]}
ValueChange->{HoldComplete[b,Null,1,OwnValues]}
1
Internal`TrackExpression[b, 1];
b = 1
ValueChange->{HoldComplete[b,1,1,OwnValues]}
1
Internal`TrackExpression[b, 1];
b[a_] := c;
Clear[b]
ValueChange->{HoldComplete[b,b[a_],c,Removed[$$Failure],DownValues]}
Internal`TrackExpression[b, 1];
z[b[a_]] ^:= c;
Clear[b]
ValueChange->{HoldComplete[b,z[b[a_]],c,Removed[$$Failure],UpValues]}
Internal`TrackExpression[b, 1];
b[a_][] := c;
Clear[b]
ValueChange->{HoldComplete[b,b[a_][],c,Removed[$$Failure],SubValues]}
Note that this will inundate you with change notifications whenever the usage popup menu shows (since there are a pile of FE tracked values there)
One thing to note is that this is part of how Dynamic
variables are handled:
Dynamic[a]
a
a = 1
ValueChange->{HoldComplete[a,1,1,OwnValues]}
1
ValueTrackTrigger
"ValueTrackTrigger"
works much like "ValueChange"
. They get the same arguments and are called under similar circumstances, except "ValueTrackTrigger"
is called only when values are truly changed and after "ValueChange"
VetoableValueChange
I've never seen this one in action, but it's worth looking at the handler it comes pre-populated with: JLink`Private`jlinkVetoFunction
. Looking at the DownValues
on this:
HoldPattern[
JLink`Private`jlinkVetoFunction[
HoldComplete[JLink`Private`sym_Symbol, JLink`Private`lhs_,
JLink`Private`rhs_, _,
DownValues]]] :> (JLink`CallJava`Private`setField[
JLink`Private`lhs, JLink`Private`rhs]; False) /;
JavaObjectQ[Unevaluated[JLink`Private`sym]]
One sees that the handler should take the argument HoldComplete[sym_Symbol,lhs_,rhs_,<no_clue_what_this_is>,DownValues]
for setting a down value. And it can clearly reject this proposed change, as the callback does, by returning False
. For some reason even after adding the handler:
Internal`AddHandler["VetoableValueChange",
Print@("VetoableValueChange" -> {##}) &
]
I still haven't seen this in action. Might be print protected??
GetFileEvent
"GetFileEvent"
I don't understand completely but I've found a few distinct usages: HoldComplete[fname_String,Identity,First]
at the start of a Get
call and HoldComplete[fname_String,Identity,Last]
at the end (I'm sure there's more meaning in there, I just don't know what it is). And when I did a documentation search with cmd+F I got these two: HoldComplete["DocumentationSearch`DocumentationSearch`", Identity, Last]
and HoldComplete[DocumentationSearch`,Identity,Last]
. Maybe these are special GetFileEvents
Mathematica records?
Misc.
The two I was most eager to see in action are "GetSymbol"
and "SetSymbol"
but I have yet to see them called. I'll update this with more stuff when I next know what's up.
Cleanup
When I'm done testing I remove all of these handlers with:
With[{h = #},
Internal`RemoveHandler[First@h, #] & /@ Last@h
] & /@ Rest@Internal`Handlers[];