5
$\begingroup$

Background

I'm trying to establish best practices for custom controllers programming. This question is about one top level aspect of it.

WRI suggested (few talks I don't remember right now) to follow e.g. LabeledSliders setup. Let's take a look at definitions of LabeledSlider then:

Needs @ "GeneralUtilities`"
PrintDefinitions @ LabeledSlider

and follow them. Here are steps you will face

  1. Evaluation: LabeledSlider DownValues

    Set of definitions to convert LabeledSlider[...]:= to valid form, basic validation for e.g. range specification is performed etc.

    At the end a valid, inert, LabeledSlider[...] is produced, ready for conversion to boxes.

  2. Typesetting: LabeledSlider UpValues+MakeBoxes

    LabeledSlider /: MakeBoxes[c_LabeledSlider, fmt]:= (... ControlToBoxes[c, fmt] )
    


  3. Typesetting: ControlToBoxes DownValues evaluation

    It handles basic syntactic sugar for the controller. Decides what to do with respect of the first argument, _Dynamic or _?NumericQ

    At the end it governs interpretation to InputForm by setting up Interpretation.

    ControlToBoxes[LabeledSlider[...] := With[
     {grid = RawBoxes @ labeledSliderBoxes[...]},
      MakeBoxes[
       Interpretation[  gird,   LabeledSlider[...]],
       fmt
      ]
    ];
    


  1. Typesetting: labeledSliderBoxes evaluation (specific/low level definitions)

    Creates the controller boxes from specification, e.g. assembles event handlers, bitmaps etc etc.

The question

I don't understand point 3. Why do we need a symbol which shares definitions for all possible GUI elements?

ControlToBoxes // PrintDefinitions contains a lot.

Which means that if you follow this convention for custom controllers and then will try to e.g. SaveDefinitions of mySlider or whatever, you will collect a bunch of unrelated code.

Can't we have e.g. {controllerName}InterpretationBoxes convention for step 3? This way each controller has independent set of definitions.

I don't see any special advantages, only problems with it.

Maybe they do this out of habit and because mma dependencies are always there anyway. This is what I think is the case but want to make sure I didn't miss anything stupid since the struggle is real and they suggest to follow this scheme.

$\endgroup$
  • $\begingroup$ Just a wild guess (didn't look into it in too much detail): Could it have to do with DynamicDump`toggleControlMakeBoxes? That seems to be used to redefine what ControlToBoxes does, no idea where it's used though $\endgroup$ – Lukas Lang Jun 11 '18 at 9:22
  • $\begingroup$ @Mathe172 maybe, I'm not sure what it is for (versioning, version switch?). Otoh those definitions seem to handle specific sym not ControlToBoxes definitions in bulk. $\endgroup$ – Kuba Jun 11 '18 at 9:26
6
$\begingroup$

As I recall, we architected things this way mainly so that FormatValues[LabeledSlider] would remain simple and consistent across all built-in control generators. We follow a similar pattern for other built-in box generators (like Grid, Row, ...).

I can't think of any reason for you to use DynamicDump`ControlToBoxes when typesetting your own custom controls. You should either define the FormatValues directly in "Step 2", or call your own utility that constructs the boxes for a particular case, depending on how you want to modularize your code.

Note that SaveDefinitions is not an issue for built-in controls, because built-in controls are Protected and ReadProtected. That makes them invisible to SaveDefinitions.

We don't typically bother to protect symbols in *Dump` or *Private` contexts, as their context name alone should warn you against calling them directly. Such symbols are, by definition, an internal implementation detail, and so referring to them directly from any other body of code is almost always a mistake.

$\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.