What are the differences between using MakeBoxes and Interpretation?
Point of conversion
A large and perhaps key difference is that MakeBoxes
(foo
) only transforms the expression into the expanded form when it is converted to Box form. It's FullForm
remains unchanged.
foo[1, 0.3] // InputForm
foo[1, 0.3`]
This means that you can operate upon the expression in every standard way without thought to a hidden internal format.
Sin /@ foo[1, 0.3`];
%[[2]]
0.29552
Interpretation
(foo2
) does not allow this:
Sin /@ foo2[1, 0.3`];
%[[2]]
The cause:
Sin /@ foo2[1, 0.3`] // InputForm
Interpretation[ Sin[Graphics[{Point[{1, 0.3}]}, Frame -> True, PlotRange -> {{-2, 2}, {-2, 2}}]], Sin[foo2[1, 0.3]]]
Held expressions
Another difference manifests when these expressions are wrapped in Hold constructs. Because MakeBoxes
works outside the standard evaluation sequence the graphic still displays. foo2
however must evaluate before Interpretation
is even part of the expression.
HoldForm[ foo[1, 0.3] ]
HoldForm[ foo2[1, 0.3] ]
Related to this point: Prevent graphics render inside held expression
Assuming that you want to create a special display form for foo
that can be used in all contexts, you should use neither of these solutions. Why?
MakeBoxes
controls howfoo
will be formatted. This is part of what you want. But the way you used it, the formatting is one-way. It will not be possible to convert the already formatted output as afoo
expression. For example, if you edit the output cell directly, or by copying the output and paste it elsewhere, it will behave asGraphics
and not asfoo
.Interpretation
is meant for typesetting only, and cannot be used in normal calculations.Interpreation["two", 2]
will format in a special way so that if you copy the formatted output, and paste it elsewhere, it will look like"two"
, but it will behave like2
. However, if you do not format it inside of a notebook and then copy it, it will not be possible to use it as a substitute for2
. For example,Head@Interpretation["two", 2]
will returnInterpretation
and notInteger
. Thus, beforeInterpretation
will start behaving equivalently to its second argument in computations, you must display it, then copy the displayed form.
What should you use then?
I suggest you use a specific combination of MakeBoxes
and Interpretation
that I presented here. This will work both ways:
- It formats the expression in a graphical way
- The formatted expression can be turned back into a computable expression (with head
foo
)
Example:
MakeBoxes[expr : foo3[x_, y_], StandardForm | TraditionalForm] :=
ToBoxes@Interpretation[
Graphics[{Point@{x, y}}, Frame -> True, PlotRange -> {{-2, 2}, {-2, 2}}],
expr
]
Under the hood, this creates an InterpretationBox
. InterpretationBox
is a special box form that already contains the expression it represents. Thus you do not need to create an explicit back-conversion rule using MakeExpression
.
The above could also be written as
MakeBoxes[expr : foo3[x_, y_], StandardForm | TraditionalForm] :=
With[{boxes = ToBoxes@Graphics[{Point@{x, y}}, Frame -> True, PlotRange -> {{-2, 2}, {-2, 2}}]},
InterpretationBox[boxes, expr]
]
This form will sometimes give more flexibility.
With foo3
you can do the following:
Neither of the two approaches you describe (foo
and foo2
) will behave this way.