Mathematica Programming » Assorted Tricks

This is a way we can assign definitions to built-in functions cleanly. This takes advantage of a two main things, a conditional definition and the power of Block . We'll use it to overload how MessageName works.

 Unprotect@MessageName;
(MessageName[o_,a:Except["usage"]]/;!TrueQ@$recursionBreakingVariable):= If[ MatchQ[o,object[_Association]], First[o][a], Block[{$recursionBreakingVariable=True},
MessageName[o,a]
]
];
Protect@MessageName;


Now we can do fun things with the MessageName operator, ::

 object[<|"a"->b,"c"->d,"e"->f|>]::a

 b


Usually that would have thrown an error:

 abject[<|"a"->b,"c"->d,"e"->f|>]::a

Message::name: Message name MessageName[abject[Association["a"->b,"c"->d,"e"->f]],"a"] is not of the form symbol::name or symbol::name::language.
 MessageName[abject[Association["a"->b,"c"->d,"e"->f]],"a"]


And the reason we did this the way we did is because if we assigned some object to a variable, variable::a would give us something meaningless. See:

 variable=abject[<|"a"->b,"c"->d,"e"->f|>];
variable::a

 variable::a


But if it's an object it will be treated differently:

 variable=object[<|"a"->b,"c"->d,"e"->f|>];
variable::a

 b


And because of the structure of the overload, MessageName still works normally in every other case.