10
$\begingroup$
a = 1;

Button["Print", a++]
Button["Print", Dynamic[a++]]
Button["Print", Dynamic[a++];]
Button["Print", {Dynamic[a++]}]

Dynamic @ a

The second Button is not supposed to change the value of a but it does.

Have I missed something or is it a bug?


Why it is not supposed to?

Button[label,action] [...] evaluates action whenever it is clicked.

Evaluation is supposed to leave Dynamic intakt and if it is part of returned result MakeBoxes will create DynamicBox which is supposed to be handled by FrontEnd which should send contents to evaluation when needed.

Yet the Button isn't creating any visible result when clicked.


While Button["Print", Dynamic[a++]] isn't useful in general, the leak is the leak.

A support case with the identification [CASE:3609709] was created

[...] I have filed an incident report with the information you provided.

[...] I have also filed a second incident report for the documentation example [...]

$\endgroup$
13
$\begingroup$

To understand this, look at the typesetting:

In[1]:= ToBoxes[Button["Print", Dynamic[a++]]] // InputForm

Out[1]//InputForm=
ButtonBox["\"Print\"", ButtonFunction :> Dynamic[a++], Appearance -> Automatic, 
 Evaluator -> Automatic, Method -> "Preemptive"]

Front end options, which includes all box options, can take Dynamic heads. That basically means that the FE will compute the value of the Dynamic and use it for the option. And that it will be updated whenever a Dynamic dependency updates.

Because Button is passing its second argument unmolested to the right-hand side of ButtonFunction, it looks like a Dynamic rhs which needs to be computed by the FE. And that computation increments a++.

At first, I was surprised that it didn't increment by virtue of simply being displayed on the screen. I.e., I might have expected a to be 2 even before you pressed the button. As it turns out, it doesn't because it's in a class of options which are treated as always held, until they're actually used. Other such options include the Initialization, Deinitialization, and TrackedSymbols options of various boxes. And too many more to list, but only a small number of the overall number of options.

So, is it a bug? Maybe. These "always-held" options certainly don't gain any benefit from Dynamic handling. However, if we added special handling for them, then we'd have to list all of the options and document why they're excluded from standard Dynamic handling, which I think would be burdensome for everyone. I think I would lean towards calling it not a bug.

I think the better thing in this case would be to properly document that the second argument of Button is passed to ButtonBoxOptions->ButtonFunction.

$\endgroup$
  • 6
    $\begingroup$ Am I the only one who gets excited upon reading "answered (by) John Fultz" on the front page? I know I am almost certainly about to learn something, and this was no exception. $\endgroup$ – Mr.Wizard May 26 '16 at 20:17
  • $\begingroup$ Great answer, thanks! Considering that, I'd say it's expected and should be left to not create exceptions. Let me suggest adding the last paragraph of your answer to Details and Options with a link to Possible Issues section where extended explanation will be given + Button[lable, Dynamic[action]] added to usage. Briefly mentioning ButtonFunction will probably be missed or will confuse a user who is unaware of subtleties. $\endgroup$ – Kuba May 26 '16 at 20:36
  • 5
    $\begingroup$ Let me abuse the fact that you are around :) Quick question, is there any purpose why Button inserts styling options even though it's a basic Button? I mean, Appearance is inserted what makes impossible to put BaseStyle->ButtonBoxOptions->Appearance->_ outside and hope that it will be inherited. Or maybe the best way is to work with RawBoxes + controllerBox so that one can use controllerBoxOptions to style them collectively? $\endgroup$ – Kuba May 26 '16 at 20:45
  • 3
    $\begingroup$ @Kuba, yes, your documentation suggestion is quite reasonable. As for the Appearance option...well, there is a reason, but I'm not sure it's a very justifiable one. Basically, it was a hack to deal with the default options we wanted for Button in v6 without breaking backward compatibility with ButtonBoxes that were generated pre-v6. It's a decision which seemed sensible (albeit a bit hacky) at the time, but looks increasingly silly today. I would be willing to call the current behavior a minor bug. $\endgroup$ – John Fultz May 28 '16 at 0:06
  • $\begingroup$ Hi,John Fultz,I know you are a frontend developer in WRI, so could I ask you a question about Mathematica premitive, about the detail, please see this thread Thanks:) $\endgroup$ – xyz Jun 19 '16 at 3:18

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.