You need to define how you expect this special object to interact with functions, and which functions should handle it. Based on your example I think you want the label to be stripped from the object when an operation is performed?
You can generally use UpSet
or TagSet
(or more frequently their Delayed counterparts) to provide handling rules as needed.
Display is most robustly handled by defining a MakeBoxes
rule for your object but Format
can work too.
Perhaps you only want a limited number of functions to operate on your object. Then:
MakeBoxes[note[val_, name_], form_] := ToBoxes[name, form]
note /: note[val_, name_] + x_. := val + x
note /: note[val_, name_] * x_. := val * x
Now:
values = {1.2, note[0.04, "nearly zero"], 0.9}
{1.2, "nearly zero", 0.9}
1 + values
{2.2, 1.04, 1.9}
Or if you want most functions to operate in this manner you can choose which heads "hold" your object unevaluated:
ClearAll[note]
MakeBoxes[note[val_, name_], form_] := ToBoxes[name, form]
$noteHolders = {List, foo};
note /: head_[a___, note[val_, name_], b___] :=
head[a, val, b] /; FreeQ[$noteHolders, head]
The global variable $noteHolders
is a list of Symbols that should not evaluate note
when the appear as the head of an expression. It may be updated at will if you define or find new functions that need to hold note
unevaluated.
Test:
values = {1.2, note[0.04, "nearly zero"], 0.9}
1 + values
{1.2, "nearly zero", 0.9}
{2.2, 1.04, 1.9}
foo[1.2, note[0.04, "nearly zero"], 0.9]
bar[1.2, note[0.04, "nearly zero"], 0.9]
foo[1.2, "nearly zero", 0.9]
bar[1.2, 0.04, 0.9]
If you want to be able copy the output "nearly zero"
and use it as input you will need to create an InterpretationBox
in the MakeBoxes
rule; see for example:
Also however see this warning about the loss of "editability" that will result: