As follows, are three different methods to answer your question. They each have there merits and flaws. The first is a literal attempt to do as you ask, but it requires modifying the behavior of a System`
function to do it. The second method deviates from what you ask by using a different binary operator for the assignment, but still links a message to the symbol. The final method does not attach a message, but provides the information through the new summary box forms. Additionally, it changes the return type to enable this.
Method 1
This can be done. It requires fiddling with some machinery that might best be left alone, but it is straightforward. You need to set an UpValue
on f
when it is found on the right hand side of SetDelayed
, e.g.
Clear[f];
f /: SetDelayed[v_Symbol, p_f] := (v::msg = "Blah, Blah, Blah!"; v = p)
f[] := "bob"
f[x_] := x^2
where all the details, like the message, what f
returns, etc. need to be adjusted to suite. But,
In[100]:= ClearAll[v]
Messages@v
v := f[q]
Messages@v
Out[101]= {}
Out[102]= q^2
Out[103]= {HoldPattern[v::msg] :> "Blah, Blah, Blah!"}
Note, I used SetDelayed
, not Set
here, because SetDelayed
is HoldRest
and Set
will evaluate f[]
before the UpValue
code can kick in.
Method 2
While the code, above, is almost literally what you ask for, it will very likely just confuse your users. Have them use this construct, instead:
Clear[f, SetVariable];
SetAttributes[SetVariable, HoldRest];
SetVariable[v_Symbol, p_f] := (v::msg = "Blah, Blah, Blah!"; v = p)
f[] := "bob"
f[x_] := x^2
The usage is a bit clunkier, e.g.
SetVariable[v, f[x]]
(* x^2 *)
v::msg
(*"Blah, Blah, Blah!"*)
But, it is less likely to confuse your users, long term. If you are absolutely bent on using an infix operator for this, you can find one that is unused here. I would consider using DoubleLeftArrow
(esc-space-<-=-esc, or \[DoubleLeftArrow]
) or DoubleRightArrow
(esc-space-=->-esc, or \[DoubleRightArrow]
to do it. Setting this up is simple
Clear[DoubleRightArrow];
SetAttributes[DoubleRightArrow, HoldFirst];
DoubleRightArrow[p_f, v_Symbol] :=
(ClearAll[v]; v::msg = "Blah, Blah, Blah!"; v = p)
with usage
f[x] \[DoubleRightArrow] v
(* x^2 *)
Note, the use of ClearAll[v]
which the original code and SetVariable
both should have to prevent circular references.
Method 3
An alternative is to create a custom head that uses a custom head that forwards the information to an inner association, then you can set up a formatting rule specifically for it and do not have to override any system functions. First, some boilerplate code to forward the keys to the inner association:
ClearAll[assocWrapper];
assocWrapper[a_Association]["Properties"] := Sort[Keys[a]~Join~{"Properties"}]
assocWrapper[a_Association][k_] := Lookup[a, k, {}]
Two things to note here. First, I would recommend added "Properties"
as shown, since it is a common accessor. Other default accessors can be added, as well, but I would keep them to a minimum as they override the keys that are present in the association. Second, I used Lookup
, instead of direct access to the association as you could add a "default"
key to the association and use that instead of any empty list.
For formatting, I would use the new summary boxes, described here. For example,
assocWrapper /: MakeBoxes[as:assocWrapper[a_Association], fmt_] :=
BoxForm`ArrangeSummaryBox[assocWrapper, as,
(* a better icon is needed here *)
IconData["MoonPhase", Length[a]/10],
{
BoxForm`SummaryItem[{"Keys: ", Length@a}]
},
(* displayed when + is clicked *)
{
BoxForm`SummaryItem[{"extra info", "available upon request"}]
},
fmt
]
Which gives

Lastly, you need to protect assocWrapper
Protect[assocWrapper];
or this will happen
a = assocWrapper[<|"key" -> "info"|>]
a["key"] = "new stuff"
b = assocWrapper[<|"key" -> "other info"|>]
b["key"]
(* "new stuff" *)
This highlights this methods disadvantage: the associations are immutable.
f
to set theusage
message forv
in addition to returning a value forv
, correct? $\endgroup$f
provides a value and a message, and given anySet
operationv=f[something]
he wantsv
to aquire that value and the message as a::usage
? But like you are implying, if you just pass aSymbol
as a third argument tof
you can do that easily. $\endgroup$