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]]

enter image description here

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] ]

enter image description here

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 how foo 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 a foo expression. For example, if you edit the output cell directly, or by copying the output and paste it elsewhere, it will behave as Graphics and not as foo.

  • 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 like 2. 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 for 2. For example, Head@Interpretation["two", 2] will return Interpretation and not Integer. Thus, before Interpretation 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:

enter image description here

Neither of the two approaches you describe (foo and foo2) will behave this way.