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
InputForm
shows that the expression is unchanged. Which leads to the question: why does this FE behavior bother you - which goals does it prevent you from accomplishing? Regarding the list of heads for which similar things happen, you can look at sayWrappersDump``WrapperToBoxes
definition (not sure if those exhaust the list). – GlossotomyHoldComplete
vsHoldAllComplete
! – SwagsmanRotate
has a specialRotateBox
, which instructs FE to treat its content differently for presentational purposes. The fundamental functions relating boxes and expressions areMakeBoxes
andMakeExpression
. As long as you base your work on expressions, you can probably ignore the specific FE representation of them, unless theMakeExpression@MakeBoxes
cycle produces something other thanHoldComplete[original_expression]
, in which case you may want to investigate it and find out the reason. – GlossotomyRotate
inside of theHoldComplete
will not be transformed intoRotateBox
. It indicates that in really the FrontEnd also parses constructs other than explicitly in the form ofBoxes
. It is really unexpected behavior... – GonagleRotationBox
, notRotateBox
. And yes,Rotate
does get transformed intoRotationBox
insideHoldComplete
inStandardForm
(default). To see that, look at the box expression of the resulting output cell (CTRL+SHIFT+E). – Glossotomylink=LinkLaunch[First[$CommandLine] <> " -mathlink"];LinkRead[link];LinkWrite[link,Unevaluated[EnterExpressionPacket[SetOptions[$Output, FormatType -> StandardForm];HoldComplete[Rotate[Style[expr, Red], 0.5]]]]];LinkRead[link]; LinkRead[link]
. I was unaware that there are such conversion rules. It obviously contradictsHoldComplete
documentation. How can it work insideHoldComplete
? – GonagleMakeBoxes
fire, that the conversion to boxes takes place, just as in previous cases, and of course with the same result. If you wrapFullForm
around the lastLinkRead[link]
, you'll see that you are getting back the original expression. – GlossotomyMakeBoxes
? – GonagleMakeBoxes
, to produce the output cells in the notebook. Even if this happens in the kernel, this is probably a separate evaluation, after the main result is produced by the kernel as an expression. It is in this sense that I meant that the main evaluation done in the kernel is in agreement with the docs onHoldComplete
. Once again - if we consider evaluation of expressions (and not their conversion into boxes), the evaluation is as documented. – GlossotomyWrappersDump`WrapperToBoxes
is related to the conversion of output expressions? – GonagleRotate
. You can do that by clearing itsReadProtected
attribute. – GlossotomyMakeBoxes
when usingPrint
:On[MakeBoxes]; Print[HoldComplete@Rotate["text", Pi/2]]
. But copy-pasting the printed output gives changed expression:HoldComplete[Rotate["text", 1.5707963267948966]]
. – Gonagle