15
$\begingroup$

Someone know why this Button works when clicked:

testModule1[]:=DynamicModule[{button, x="",randomGrid},
    button=Button["Create table",x=RandomInteger[10,{3,3}]//MatrixForm];
    Deploy@Panel@Dynamic@Column[{button,x}]
]
testModule1[]

test1

and this not:

testModule2[]:=DynamicModule[{button, x="",randomGrid,ff},
    ff:=(x=RandomInteger[10,{3,3}]//MatrixForm);
    button=Button["Create table",ff];
    Deploy@Panel@Dynamic@Column[{button,x}]
]
testModule2[]

test2

I have some big functions to put into x, and I would like to organize my code in the second way.

$\endgroup$
6
  • 1
    $\begingroup$ It is my understanding (correct/incorrect) that SetDelayed doesn't work inside the DynamicModule. $\endgroup$ Commented Jul 24, 2013 at 22:46
  • 5
    $\begingroup$ You can use ff[]:=... and then ff[] instead of ff inside the button code, and that will work. This does not explain however why OwnValues don't work. $\endgroup$ Commented Jul 24, 2013 at 22:54
  • 4
    $\begingroup$ Ok, here is a kind of an explanation. As @MikeHoneychurch noted, the delayed evaluation is performed in fact immediately (or at least so it looks to me too). Then, x is assigned some random matrix, and f is out of the game for the OwnValues scenario. You can look at the generated box expression in the FE for your button, to see this. However, for DownValues, while the assignment is again performed immediately, the DownValues get stored by DynamicModule with the help of DynamicModuleValues option. This keeps f[] in the button code operational. $\endgroup$ Commented Jul 24, 2013 at 23:05
  • 1
    $\begingroup$ Yes!.. ff[] works, DynamicModules are very strange (or would be all MMA evaluation system?)!.. Tks @Leonid $\endgroup$
    – Murta
    Commented Jul 24, 2013 at 23:43
  • 1
    $\begingroup$ @Murta No problem. I agree that Dynamic can be not quite intuitive. I usually find workarounds for what I need from it, but I can't say that I have any deep understanding of it. $\endgroup$ Commented Jul 24, 2013 at 23:47

4 Answers 4

14
$\begingroup$

Well, Mike Honeychurch and Leonid Shifrin have pretty much covered the ground, but I have one thing to add, which, while based only on observed behavior, I think helps explain what's going on.

Set and SetDelayed both create OwnValues is the form HoldPattern[symbol] :> code. The difference is that code is unevaluated in the case of SetDelayed. DynamicModule stores ownvalues as initialization assignments, symbol = value. This makes a difference because the expression value is or appears to be created by executing code. So in the case of SetDelayed, the code ends up being evaluated anyway, not when the SetDelayed is first evaluated, but when the ownvalue it creates is stored in the DynamicModule output.

One can observe this in the following

testModule3[] := 
 DynamicModule[{button, x = "", ff}, 
  ff := (Print["Boo!"]; x = RandomInteger[10, {3, 3}] // MatrixForm);
  button = Button["Create table", ff];
  Deploy@Panel@Dynamic@Column[{button, x}]]
testModule3[]
(* --> Boo! *)
(* Panel with non-working button *)

The "Boo!" is printed even though button was not pressed. If Module replaced DynamicModule, the Print statement would not have been executed and "Boo!" would not be printed.

The problem (for the designers of DynamicModule) can be seen in this:

Clear[x]

ff1 = x + 4;
x = 3;
ff2 = x + 4;
ff3 := x + 4;
OwnValues@ff1
OwnValues@ff2
OwnValues@ff3

(* {HoldPattern[ff1] :> 4 + x} *)
(* {HoldPattern[ff2] :> 7} *)
(* {HoldPattern[ff3] :> x + 4} *)

One can see that ff1 and ff3 are equivalent, even if not strictly identical. But why should this be a problem? Why not store these ownvalues in the form they are above? In that case, DynamicModule would work just like the rest of Mathematica (just like Module in Kuba's second solution). The answer I think is fairly simple, but for me it is just a guess: speed. Just as Compile is limited to a simpler subset of functionality, so is dynamic interactivity and what the front end can handle.

The kind of assignment the front end can do without communicating with the kernel is probably just a simple assignment (such as in C, say). It does not create a pattern but stores a value in the front end. Primarily I think the developers have in mind number assignments, but clearly any expression is allowed on the RHS. This allows such things as Animators to be efficient, for instance. In the case of complicated RHS expressions, the front end asks the kernel to evaluate it and send the value back. Efficiency in this sort of end-use case and minimizing computational overhead is clearly part of the design of the Dynamic system.

That's how the basic principles seem to me. That they are part of the design can be inferred from this, and the following section in Advanced Dynamic Functionality. The motivations I have guessed at may be off, and there may be further internal considerations that are yet hidden from me.


P.S. Here's another variation to solve the OP's problem, which is consistent with the explanation above: Use Hold and ReleaseHold to mimic the behavior of SetDelayed. Whether Set or SetDelayed is used to define ff does not matter. The "value" of ff in either case is the held expression, which is what is stored in the output cell (and can seen via Cell > Show Expression).

testModule4[] := DynamicModule[{button, x = "", ff},
  ff := Hold@(x = RandomInteger[10, {3, 3}] // MatrixForm);
  button = Button["Create table", ReleaseHold@ff];
  Deploy@Panel@Dynamic@Column[{button, x}]]
$\endgroup$
3
  • $\begingroup$ Tks Michael. Very elucidative explanation. $\endgroup$
    – Murta
    Commented Jul 25, 2013 at 5:46
  • $\begingroup$ +1, especially for the workaround/solution. If this is done for reasons of speed, I guess I dislike this choice. $\endgroup$ Commented Jul 25, 2013 at 10:50
  • 1
    $\begingroup$ @JacobAkkerboom Thanks. I added a reference supporting the speed hypothesis. I would like it better if the references for Set, SetDelayed, and/or DynamicModule mentioned this limitation. $\endgroup$
    – Michael E2
    Commented Jul 25, 2013 at 13:21
7
$\begingroup$

There are many issues arasing while creating complex DynamicModules. Usually I'm not even sure what to ask about.

This is how I would do this in order to avoid putting procedures inside Button:

    testModule2[] := DynamicModule[{randomGrid, x = "", button},
                            button = Button["Create table", ff];
                            Deploy@Panel@Column[{button, Dynamic@x}]
                            , Initialization :> (

                                ff := (x = RandomInteger[10, {3, 3}] // MatrixForm);

                                                 )

                                  ]

The less content wrapped with Dynamic, the better.

Of course it is not an answer to your question. I think Mike Honeychurch is right but I miss some kind of tutorial "how to make efficient use of scoping constructs and Dynamic for CDF creating".

Why do I think it is important?, because good luck with only DynamicModule and minimal content wrapped with Dynamic if you want to scope all names. Notice, that in above code ff is not scoped. If you need this I recommend adding Module.

  testModule2[] := Module[{ff},  
                       DynamicModule[{randomGrid, x = "", button},
                        button = Button["Create table", ff];
                        Deploy@Panel@Column[{button, Dynamic@x}]
                       , Initialization :> (     
                          ff := (x = RandomInteger[10, {3, 3}] // MatrixForm);
                        )]]

Leonid Shifrin's observation about DownValues and OwnValues is striking. It is good to know that. It can help you make such code with only DynamicModule, however I like to have main structure of the CDF on top while procedures etc. at the end. The code is more transparent then, at least IMO.

$\endgroup$
4
  • $\begingroup$ what does randomGrid refer or relate to? It is not in the expressions and code works without it. $\endgroup$
    – ubpdqn
    Commented Jul 25, 2013 at 1:25
  • $\begingroup$ @ubpdqn it is from the question code :) $\endgroup$
    – Kuba
    Commented Jul 25, 2013 at 4:47
  • $\begingroup$ +1, using Initialization is in my opinion the most natural solution. $\endgroup$ Commented Jul 25, 2013 at 11:08
  • $\begingroup$ @JacobAkkerboom New note. scoping ff inside DynamicModule is possible, we just have to create DownValues instead OwnValues: ff[]:= .... Not sure why though $\endgroup$
    – Kuba
    Commented Feb 20, 2014 at 12:37
5
$\begingroup$

Unless I am mistaken (which is entirely possible) I recall reading somewhere that SetDelayed is treated as Set within DynamicModule.

When I take your second block of code and use Module instead of DynamicModule it seems to work as you want (but x etc are now kernel variables of course).

$\endgroup$
1
  • $\begingroup$ This toy code is a small part of a CDF file. So I need the Dynamic part. The ff[] Leonid solution works nice tks! $\endgroup$
    – Murta
    Commented Jul 24, 2013 at 23:44
2
$\begingroup$

I don't know if I like my interpretation of the examples below anymore. I will just leave them here though

Here is more crazyness. I think Michael explains quite well what happens. The only thing new this first section shows is that new symbols get created sometimes, which makes it seem functions point to the wrong thing, but that actually does not matter.

DynamicModule[{button, x = 0, ff, `},
 ff := (++x);
 var = Hold[x];
 var2= z;
 button = Button["setX", ff];
 Dynamic[Column@{button, x, Hold[x], Hold[x], var, OwnValues[ff], z, var2}]
 ]
Hold[FE`x$$213]

Hold[FE`x$$213]

Hold[x$314]

{HoldPattern[FE`ff$$213] :> 1}

FE`z$$225

z$1236

Conclusions: It is possible for a variable to point to the wrong thing, like with var, or var2. ff does point to right thing, but it's code gets evaluated. Probably: The pointing to the wrong thing is not caused by the DynamicModule changing it's x all the time. I suppose it really wants to evaluate the code attached to symbols and not have it refer to any of the used symbols.

DownValues

Also note

DynamicModule[{gg = 0, x},
 OwnValues[gg] = {HoldPattern[gg] :> x};
 Dynamic[{OwnValues[gg], Hold[x]}]
 ]
 {{HoldPattern[FE`gg$$270]:>FE'x$$270},Hold[FE`x$$270]}

but

DynamicModule[{gg = 0, x = 0},
 OwnValues[gg] = {HoldPattern[gg] :> x};
 Dynamic[{OwnValues[gg], Hold[x]}]
 ]
 {{HoldPattern[FE`gg$$271]:>0},Hold[FE`x$$271]}

It seems it does not matter if we set something using OwnValues or in the regular way, using Set or SetDelayed. It seems that a function definition can even be changed afterwards, like in

DynamicModule[{gg = 0, x},
 OwnValues[gg] = {HoldPattern[gg] :> x};
 x = 0;
 Dynamic[{OwnValues[gg], Hold[x]}]
 ]
{{HoldPattern[FE`gg$$312]:>0},Hold[FE`x$$312]}

Order of evaluation

The order of evaluation seems only to depend on the order in which they appear in the list of local symbols in the first argument of DynamicModule.

DynamicModule[{gg, x},
 x := (Print["x"]; {2});
 gg := (Print["gg"]; First@HoldComplete[x]; Print["ggDone"]);
 ]
gg (*print*)

x (*print*)

ggDone (*print*)

x (*print*)

Null

and

DynamicModule[{gg, x},
 x := (Print["x"]; {2});
 gg := (Print["gg"]; First@HoldComplete[x]; Print["ggDone"]);
 ]
x (*print*)

gg (*print*)

x (*print*)

ggDone (*print*)

Null (*print*)

We also see that it uses the "old" definitions of symbols to generate the definitions of the new symbols. I suppose it never does use a new definition in the definition of another new symbol.

I am lost :). I don't think I like this much.

$\endgroup$
2
  • $\begingroup$ @Kuba again, thanks for editing :). I really like the solution of the code blocks inside the "orangy blocks" :). Now the variables with a Context (and backtick) in front of them display beautifully. I'll see how you did it. $\endgroup$ Commented Jul 26, 2013 at 10:29
  • $\begingroup$ You are welcome :) ">"+ 5 " " $\endgroup$
    – Kuba
    Commented Jul 26, 2013 at 10:33

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

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