As I learned recently there are some types of expressions in Mathematica which are automatically parsed by the FrontEnd.
For example if we evaluate HoldComplete[Rotate[Style[expr, Red], 0.5]]
we see that the FrontEnd does not display the original expression:
Is it possible to control such behavior of the FrontEnd?
And is it possible to get complete list of expressions those are parsed by the FrontEnd automatically?
EDIT
We can see calls to MakeBoxes
when using Print
:
On[MakeBoxes]; Print[HoldComplete@Rotate["text", Pi/2]]
But copy-pasting the printed output gives changed expression: HoldComplete[Rotate["text", 1.5707963267948966]]
. It shows that Print
does not respect HoldComplete
.
When creating output Cell
there should be calls for MakeBoxes
too. Is there a way to see them?
I have found a post by John Fultz with pretty clear explanation of how graphics functionality works:
In version 6, the kernel has
absolutely no involvement whatsoever
in generating the rendered image.
The steps taken in displaying a
graphic in version 6 are very much
like those used in displaying
non-graphical output. It works as
follows:
1) The expression is evaluated, and
ultimately produces something with
head Graphics[]
or Graphics3D[]
.
2) The resulting expression is passed
through MakeBoxes
. MakeBoxes
has a
set of rules which turns the graphics
expression into the box language which
the front end uses to represent
graphics. E.g.,
In[9]:= MakeBoxes[Graphics[{Point[{0, 0}]}], StandardForm]
Out[9]= GraphicsBox[{PointBox[{0, 0}]}]
Internally, we call this the "typeset"
expression. It may be a little weird
thinking of graphics as being
"typeset", but it's fundamentally the
same operation which happens for
typesetting (which has worked this way
for 11 years), so I'll use the term.
3) The resulting typeset expression is
sent via MathLink to the front end.
4) The front end parses the typeset
expression and creates internal
objects which generally have a
one-to-one correspondence to the
typeset expression.
5) The front end renders the internal
objects.
This means that the conversion is performed in the Kernel by a call to MakeBoxes
.
This call can be intercepted through high-level code:
list = {};
MakeBoxes[expr_, form_] /; (AppendTo[list, HoldComplete[expr]];
True) := Null;
HoldComplete[Rotate[Style[expr, Red], 0.5]]
ClearAll[MakeBoxes];
list
Here is what we get as output:
One can see that MakeBoxes
does not respect HoldAllComplete
attribute.
The list of symbols which are auto-converted before sending to the FrontEnd one can get from FormatValues
:
In[1]:= list =
Select[Names["*"],
ToExpression[#, InputForm,
Function[symbol, Length[FormatValues@symbol] > 0, HoldAll]] &];
list // Length
During evaluation of In[1]:= General::readp: Symbol I is read-protected. >>
Out[2]= 162
There are two aspects to what you witness. First, transcription of the expression you entered into boxes and rendering those boxes by Front-End. By default the output is typeset using StandardForm, which has a typesetting rule to render graphics and geometric transforms. If you use InputForm, there are no such rule. You can control which form is used via Preferences->Evaluation.
You can convince yourself that HoldComplete correctly did its job by using InputForm or FullForm on the input, or using InputForm display on the output cell.
EDIT Using the OutputForm:
In[13]:= OutputForm[%]
Out[13]//OutputForm= HoldComplete[Rotate[expr, 0.5]]
In regard to your question about complete list of symbols, it includes Graphics, geometric operations, and possibly others, but I do not know of the complete list.
Not quite an answer, but in Preferences > Evaluation there are options to "Only use textual boxes when converting (input|output) to typeset forms."
If you check these, then using Cell > Convert To... > StandardForm etc... will show the Rotate[..] instead of the visually rotated result.
John Fultz has recently answered my question on converting TableForm
to "typeset" expressions and it is worth to cite it here since it amplifies (while partially contradicts) the general explanation cited in my previous answer:
ToBoxes
is returning precisely what
the kernel sends to the front end
without variation (except, in the
general case, for the evaluation
semantics and side effects possibly
being different, but that's not an
issue in your example).
The issue is that the front end has
two different specifications for
specifying GridBox
options... one of
which dates back to version 3, and the
other, more expansive set dates to
version 6. The front end understands
both sets of options, but
canonicalizes anything it receives to
the version 6 options.
GridBox
is the only box which has had
such a wholesale change of options,
and it was necessary to support new
functionality we added in v6. But the
front end will continue to understand
the old options for a seriously long
time (probably forever), as the old
options show up not only in certain
kernel typesetting constructs, but in
legacy notebook files.
ToBoxes[]
of TableForm
is creating the
legacy options, as there's been no
need to update the typesetting of
TableForm
in a while (ToBoxes[]
of
Grid
, on teh other hand, uses modern
options). The conversion is done by
the front end. You could rely on the
front end to do the conversion for
you, or you could figure out how the
options map yourself.
So in this case the final stage of the conversion of the expression is done by the FrontEnd.