Conversion of expressions by the FrontEnd
Asked Answered
G

4

7

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:

Screenshot

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?

Gonagle answered 11/4, 2011 at 6:44 Comment(13)
I don't agree with the statement that FrontEnd does not display the original expression in this case. What you see is purely a display mode, it does not modify the code itself in any way. For example, the 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 say WrappersDump``WrapperToBoxes definition (not sure if those exhaust the list).Glossotomy
Alexey, good catch regarding HoldComplete vs HoldAllComplete !Swagsman
@Leonid In which cases this "display mode" plays the role? In which it does not? How it works? All of these are the questions I am interested in.Gonagle
@Alexey Most of what FrontEnd does is related to this or that type of boxes. For example, Rotate has a special RotateBox, which instructs FE to treat its content differently for presentational purposes. The fundamental functions relating boxes and expressions are MakeBoxes and MakeExpression. As long as you base your work on expressions, you can probably ignore the specific FE representation of them, unless the MakeExpression@MakeBoxes cycle produces something other than HoldComplete[original_expression], in which case you may want to investigate it and find out the reason.Glossotomy
@Leonid But Rotate inside of the HoldComplete will not be transformed into RotateBox. It indicates that in really the FrontEnd also parses constructs other than explicitly in the form of Boxes. It is really unexpected behavior...Gonagle
@Alexey I actually misspelled the name - it is RotationBox, not RotateBox. And yes, Rotate does get transformed into RotationBox inside HoldComplete in StandardForm (default). To see that, look at the box expression of the resulting output cell (CTRL+SHIFT+E).Glossotomy
@Leonid Conversion is made purely in the kernel: link=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 contradicts HoldComplete documentation. How can it work inside HoldComplete?Gonagle
@Alexey I am not convinced by your example. What I think is happening is that the resulting expression you are getting from the link is the same as the input one - that is, no conversion is taking place in the kernel. It is when the output cell is formed and perhaps internal rules for MakeBoxes fire, that the conversion to boxes takes place, just as in previous cases, and of course with the same result. If you wrap FullForm around the last LinkRead[link], you'll see that you are getting back the original expression.Glossotomy
@Leonid Do you mean that conversion is made by the FrontEnd that has its own analog of the evaluator with some definitions for FrontEnd's MakeBoxes?Gonagle
@Alexey I don't know how the FE works in enough detail to answer that. What I meant is that FE somehow initiates the call to MakeBoxes, 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 on HoldComplete. Once again - if we consider evaluation of expressions (and not their conversion into boxes), the evaluation is as documented.Glossotomy
@Leonid How had you found that WrappersDump`WrapperToBoxes is related to the conversion of output expressions?Gonagle
@Alexey I looked at the top-level code for Rotate. You can do that by clearing its ReadProtected attribute.Glossotomy
@Leonid 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]].Gonagle
G
6

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:

screenshot

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
Gonagle answered 28/4, 2011 at 6:19 Comment(1)
+1 for the useful info, but I still disagree with your conclusion from the above that "MakeBoxes does not respect HoldAllComplete attribute". What we see is a display mode, if you use FullForm on list, you will see the original expression. I don't think there is any function in the whole mma language that (intentionally, by design, rather than due to some bug) does not respect any of its attributes - this would be a very big deal otherwise, would greatly undermine the language consistency. The users should not even be able to write such a function, and neither should the developers.Glossotomy
C
5

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.

enter image description here

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.

Christiano answered 11/4, 2011 at 12:26 Comment(0)
E
2

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.

Erie answered 11/4, 2011 at 15:12 Comment(0)
G
1

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.

Gonagle answered 7/6, 2011 at 2:52 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.