20
$\begingroup$

Background

So, one could be surprised by the fact that:

Hold @ Grid[{{1, 2}}]
 (*or*)
Hold @ Graphics @ Disk[]

enter image description here

This issue and methods of prevention are discussed in Prevent graphics render inside held expression.

I need further explanation though.


Questions

Recall that the rendering of Graphics has nothing to do with evaluation. It is done entirely in typesetting. And therefore, a robust solution will treat this as a problem of typesetting, and not as a problem of evaluation. - John Fultz answer

  • Question 1 What is the typesetting in Mathematica? What procedures does it include?

  • Question 2 Why isn't MakeBoxes using custom rules called Evaluation?

    I understand that

    Hold @ RawBoxes @ GraphicsBox[DiskBox[{0, 0}]]
    

    Will be displayed as a black disk, FrontEnd taking care of GraphicsBox is natural.

    But I don't know why this is done this way:

    MakeBoxes @ Graphics[Disk[]]   
      (*GraphicsBox[DiskBox[{0, 0}]]*)
    
    MakeBoxes @ Whatever[Disk[]] (*expected*)
      (*RowBox[{"Whatever", "[", RowBox[{"Disk", "[", "]"}], "]"}]*)
    

    For me using custom translations while parsing input is more than just typesetting.

  • Question 3 Why this design choice? Couldn't Grid, Graphics just evaluate to GraphicsBox? (what would allow Hold to prevent rendering)


Except of confusion this makes working with

InputField[Dynamic@x, Hold[Expression]]

pointless. Because as soon as you type something with custom MakeBoxes rules you will have to retype that to edit.

Am I overreacting? Have I missed something that makes this behavior really appreciated?

$\endgroup$
  • $\begingroup$ The whole point of Graphics is that it is an inert representation of graphics. Since version 6, it doesn't evaluate, it doesn't do anything, etc. It just represents graphics. The front end then can show it as text, but it can also show it as an image. Both are just ways to display the same Mathematica expressions. In StandardForm it shows it as an image and in InputForm as text. $\endgroup$ – Szabolcs May 4 '16 at 13:23
  • $\begingroup$ I don't know, maybe we're thinking of this in very different ways or I just don't understand your question, but this behaviour makes perfect sense to me. It seems like a very elegant way to add graphics capability to a system that prefers to avoid side effects: just use declarative graphics, and render the graphics expression automatically. $\endgroup$ – Szabolcs May 4 '16 at 13:25
  • $\begingroup$ @Szabolcs It's not only about Graphics but whatever that has specific rules for MakeBoxes. As I said, I understand RawBoxes@GraphicsBox[DiskBox[{0, 0}]] is meant to be a picture. I just don't understand why Graphics,without evaluation, is converted to GraphicsBox instead of RowBox "Graphics" "[" .... I don't claim I'm right. Maybe I'm missing something, well obviously I am missing something, that's why there is a question. $\endgroup$ – Kuba May 4 '16 at 13:31
  • $\begingroup$ @Szabolcs also, "disabling" specific MakeBoxes still allows you to write GraphicsBox and see images without evaluation. So the behavior I'm talking about is nothing more but shortcut which generates problems. In my opinion, but still, I am rather asking for explanation than complaining :) $\endgroup$ – Kuba May 4 '16 at 13:34
  • 1
    $\begingroup$ @Karsten 7. Why have you deleted your answer? It doesn't answer the essence of the question but provides good workarounds for the InputField issue. I think it is worth to keep it as a partial answer demonstrating that the problem with InputField resulting from the described design choices is not so severe as one can imagine... $\endgroup$ – Alexey Popkov May 9 '16 at 6:54
10
$\begingroup$

Question 1:

What is the typesetting in Mathematica? What procedures does it include?

I think that this 2008 year MathGroup post by John Fultz completely answers this question, so I'll cite it here:

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.

In version 6, the front end, and only the front end can render graphics (unless you use the legacy PostScript scheme via <<Version5`Graphics`, in which the kernel does the hard job of rendering the graphic to a simple subset of PostScript, and the FE has the considerably easier job of merely rendering the PostScript to the screen).


Question 2:

But I don't know why this is done this way:

MakeBoxes @ Graphics[Disk[]]   
  (*GraphicsBox[DiskBox[{0, 0}]]*)

MakeBoxes @ Whatever[Disk[]] (*expected*)
  (*RowBox[{"Whatever", "[", RowBox[{"Disk", "[", "]"}], "]"}]*)

This is because typesetting rules are applied in a chain where the choices of branches depend of the previous choices (which in the first place are determined by the parent Heads). Citing the Documentation for MakeBoxes (emphasis is mine):

MakeBoxes is NOT automatically called on the results it generates. This means that explicit MakeBoxes calls must typically be inserted into definitions that are given.

We can Trace the typesetting and see what actually happens:

ExportString[
 Trace[MakeBoxes@Graphics[Disk[]], Typeset`MakeBoxes, TraceInternal -> True], "Text"]
"{{{HoldForm[Typeset`MakeBoxes[Graphics[Disk[]], StandardForm, Graphics]], 
   HoldForm[Typeset`ReleaseHold[System`Dump`InheritAmbientSettings[
      With[{System`Dump`boxes = Typeset`MakeBoxes[Disk[], StandardForm, 
          Graphics], System`Dump`options = System`Dump`GraphicsOptionsToBoxes[
          {}, StandardForm, Graphics]}, GraphicsBox[System`Dump`boxes, 
        System`Dump`options]], Graphics]]], 
   {{{{HoldForm[Typeset`MakeBoxes[Disk[], StandardForm, Graphics]], 
       HoldForm[DiskBox[{0, 0}]]}}}}}}}"

From the above we see that when the Head of expression is Graphics the call to MakeBoxes is redirected to Typeset`MakeBoxes with Graphics as the third argument. But without the head Graphics there is no call to Typeset`MakeBoxes and everything is handled by MakeBoxes:

Trace[MakeBoxes@Whatever[Disk[]], TraceInternal -> True]
{HoldForm[MakeBoxes[Whatever[Disk[]]]], 
 {HoldForm[MakeBoxes[Whatever, StandardForm]], HoldForm["Whatever"]}, 
 {HoldForm[MakeBoxes[Disk[], StandardForm]], 
  {HoldForm[MakeBoxes[Disk, StandardForm]], HoldForm["Disk"]}, 
  HoldForm[RowBox[{"Disk", "[", "]"}]]}, 
 HoldForm[RowBox[{"Whatever", "[", RowBox[{"Disk", "[", "]"}], "]"}]]}

Question 3:

Why this design choice? Couldn't Grid, Graphics just evaluate to GraphicsBox? (what would allow Hold to prevent rendering)

Of course such question should best be answered by the developers but I think that a part of the answer is already clear from the "Question 2" section: parsing of expression into BoxForms (i.e. typesetting) is not intended to be a 1-to-1 operation, interpretation of a language construct depends on its neighborhood (especially on the parent expression in which it is embedded). Of course it is already a design choice but from this choice follows that typesetting cannot be done via OwnValues. And as Mr.Wizard correctly points out in his answer, it would be very inconvenient from practical point of view if the expressions given in the high-level Mathematica language would automatically evaluated into their low-level BoxForm representation during usual process of working with them in the WL. I'm also glad that the most of the time in the WL we work only with the short and predictable high-level representation. At the same time, the language allows to control the process of conversion into BoxForms if it is strictly needed and it is also easy to prevent rendering of Graphics without loosing the ability to render it later, some ideas you can take from my shortInputForm function and the original thread when the first version of this function was developed, and the MakeBoxesStop function by Leonid Shifrin from this thread can also be of interest for you:

MakeBoxesStop[Graphics[Disk[]]]
Graphics[Disk[List[0, 0]]]

The InputField issue

Except of confusion this makes working with

InputField[Dynamic@x, Hold[Expression]]

pointless. Because as soon as you type something with custom MakeBoxes rules you will have to retype that to edit.

The reason for this is that the contents of the input field is rendered in StandardForm when the value of Dynamic variable x is changed (including the situation when you change it via the InputField itself, i.e. by typing and pressing Enter).

As a simple workaround I can suggest to work with String, then convert it into expression using MakeExpression. You can include the syntax checking into InputField for example as follows:

InputField[Dynamic@x, String, Background -> Dynamic[If[SyntaxQ@x, Yellow, Red]]]

Now for syntactically correct WL expressions the input field will become yellow, but for incorrect it will become red.

Another workaround is suggested by Karsten 7. in his (now deleted) answer: InputField allows to work with raw boxes when the second argument is Boxes. When working with raw boxes you keep the same predictable and stable behavior of the input field as in the case of working with string input but allowed to use 2D formatting, paste already rendered images and other objects. What is significant, the appearance of the input field won't change after you press Enter and hence you won't have to retype anything!

Grid[{{"InputField", 
   "Converted to HeldExpression in InputForm"}, {InputField[Dynamic[x], Boxes, 
    BaseStyle -> "Input"], Dynamic[InputForm@ToExpression[x, StandardForm, Hold]]}}, 
 Frame -> All]

output

$\endgroup$
5
$\begingroup$

I am going to attempt to answer your questions off the cuff. I have been somewhat inactive on this site recently and also not using Mathematica much, so I am surely not at my best, so "take this with a grain of salt" as they say.

  • Question 1 What is the typesetting in Mathematica? What procedures does it include?

Typesetting is anything that is done for or by the Front End that is not part of Kernel evaluation, e.g. conversion to Box form. It certainly can entail Kernel evaluation, but if this evaluation takes place for the purpose of conversion to Box form it may be considered typesetting.

  • Question 2 Why isn't MakeBoxes using custom rules called Evaluation?

Of course there is evaluation involved as noted above but it seems useful to discriminate between evaluation that takes place directly on behalf of the program and that which takes place on behalf of the Front End interface.

  • For me using custom translations while parsing input is more than just typesetting.

You are free to make that distinction, however it seems equally reasonable to consider input processing with $PreRead etc. as distinct from main evaluation. Additional specificity is required if we wish to discuss multiple forms of evaluation.

  • Question 3 Why this design choice? Couldn't Grid, Graphics just evaluate to GraphicsBox? (what would allow Hold to prevent rendering)

I cannot speak for the designers but I am quite glad that they did not do what you suggest! Box form is normally not something that an average user works with directly; it is almost a language unto itself that it used by the Front End for interface purposes. It would be quite confusing and arduous if we had to work with Box form any time we wished to operate on Graphics etc. code.

Consider the example I gave in answer to What is the equivalent of a prototypical Manipulate in lower level functions? and imagine if a simple Slider directly evaluated into the full Box form in the lower part of that post. As I said there: I am rather glad we don't have to do "low level" FrontEnd programming very often!

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.