32
$\begingroup$

Dynamic and the related functionality strikes me as a very unique way to build quick and dirty personal GUIs which are great for experimentation.

I suspect that this is only because of my lack of experience with GUI building tools and other programming languages. There must be something similar out there, perhaps something that was an inspiration of Dynamic. Maybe the paradigm even has a standard name that I don't know about.

So where did the idea come from? What inspired Dynamic? What other languages use a similar paradigm? Or is Dynamic a unique invention of WRI?

The basic idea seems to be to connect variables with visual controls (Slider[Dynamic[x]]) and live displays directly. Multiple controls and displays can map to the same variable. This is quite different from the slots and signals approach that Qt takes (the only serious GUI library I ever used).


I want to clarify at the start that I am not looking for "alternatives" to use in practical work. I am not talking about R's shiny or IPython's interactive widgets, which are all inspired by Mathematica's more narrow Manipulate function. I am looking for the origin of the general principles that Dynamic uses. To give an analogy, if I asked the same question about the principles the Mathematica language is built on, a useful answer would mention the keywords term rewriting and the Pure programming language or the Maude theorem prover, which, together with Mathematica, are based on this idea.

$\endgroup$
  • $\begingroup$ As I said I don't have much experience with GUI building, so I am taking a risk here: others who used many GUI libraries may find this question trivial and naïve. Please comment before closing. $\endgroup$ – Szabolcs Sep 16 '16 at 13:09
  • $\begingroup$ @Leonid Is this sort of (accidental) mistake an inherent problem of 2-way binding? Dynamic[x = 2 y], Dynamic[y = 2 x] $\endgroup$ – Szabolcs Sep 16 '16 at 13:45
  • $\begingroup$ @Leonid These comments are growing to be answer-sized. $\endgroup$ – Szabolcs Sep 16 '16 at 13:52
  • $\begingroup$ @LeonidShifrin I guess there are two ways to consider this question: 1) How is this implemented in Mathematica, i.e. in the source code to which we have no access to, or 2) what paradigm are we using when we use Dynamic. For example, when we are using React/Redux we are using the functional reactive paradigm, what are we using when we are using Dynamic? I meant to say that we are not using FRP. $\endgroup$ – C. E. Sep 16 '16 at 14:16
  • $\begingroup$ Let us continue this discussion in chat. $\endgroup$ – Leonid Shifrin Sep 17 '16 at 11:37
32
$\begingroup$

General

With a disclaimer that I am by far not an expert in this field, I will still try to answer. Perhaps this answer could then be improved by others more knowledgable than me.

Model

From the end-user perspective, I think that Dynamic implements a UI model that, in javascript community, has been known as a 2 - way data binding. Basically, this model divides the application (roughly) into a model - which contains the relevant data that may change, and a view - a set of UI elements facing the end user. The 2-way data binding simply means that whenever model is changed, the view gets updated, and vice versa. The most prominent example of a framework built on this idea, in the js world, is probably Angular.js.

However, this model by itself is not a language-level construct, but rather a framework-level one. What I mean by this is that the 2-way data binding effect can be achieved by many different means. An even more interesting question is probably what should be the underlying language-level paradigm used to implement such a scheme (or other reactive schemes) most naturally.

Paradigm

Arguably, the general paradigm behind this is that of Reactive Programming.To quote the linked Wikipedia article,

Reactive programming is a programming paradigm oriented around data flows and the propagation of change. This means that it should be possible to express static or dynamic data flows with ease in the programming languages used, and that the underlying execution model will automatically propagate changes through the data flow.

A sub-paradigm of Reactive Programming that may be of particular interest in the context of functional languages is Functional Reactive Programming, which

is a programming paradigm for reactive programming (asynchronous dataflow programming) using the building blocks of functional programming (e.g. map, reduce, filter).

The idea is to represent streams of events in declarative manner, in many ways resembling lazy sequences, and then one can use many of the standard FP tools like map, reduce (Fold in Mathematica), filter (Select in Mathematica), etc. to process those streams of events in a declarative way.

In javascript, for example, one can program in this paradigm using RxJS - reactive extensions to javascript. There are also functional languages that natively support this paradigm (some that I know about I listed below).

Note, however, that while Mathematica has some of the necessary language ingredients to program in this way, its UI event model is not really exposed to the user (like it is e.g. in javascript), and instead we get the much more high-level Dynamic construct, which is already built on top of an event model. Therefore, my understanding is that one can't really utilize this paradigm directly for UI programming in Mathematica, although using Dynamic de facto means using a form of reactive programming implicitly.

In this sense, Dynamic feels more like UI - building in a framework like Angular, where the actual propagation of changes happens behind the scenes (digest cycle in Angular), and normally you don't interact with it directly, although implicitly are using it all the time. Actually, Dynamic feels even more high-level, since in Angular you can get a hold of the internals if you really want to (although in the context of a framework like Angular the need to do so would reflect either sub-optimal use of the framework, or that framework itself uses leaky abstractions - but at least that is possible to do).

Resources

Some resources:

Some of the languages that fully support FRP:

I would in particular emphasize Red, which is also a symbolic functional programming language. If you check their blog (linked above), they have a number of examples illustrating fast UI construction via reactive programming that looks pretty similar to Dynamic in Mathematica.

An example: Todo MVC

This is probably the most famous example used to test dynamic UI frameworks. I will provide implementations for Angular.js and Mathematica, to compare them and get a little feel for the similarities and differences.

Mathematica vs. Angular.js - implementations

First, Mathematica code (don't claim that it is optimal):

DynamicModule[{todos = {}, currentTodo = Null},
  Framed[#, FrameStyle -> Gray] &@Column[{
    Panel[
      Style["TODO List", FontFamily -> "Al Tarikh", FontSize -> 20],
      ImageSize -> {300, Automatic}
    ]
    ,
    EventHandler[
      InputField[
        Dynamic[currentTodo],
        String,
        FieldHint -> "What needs to be done?",
        ImageSize -> {300, 20}
      ],
      "ReturnKeyDown" :> 
         If[currentTodo =!= Null,
           PrependTo[todos, currentTodo];
           currentTodo = Null;
         ]
    ]
    ,
    Dynamic[
      Column[
        Map[
          Panel[
            Row[{
              Pane[#, ImageSize -> {250, Automatic}], 
              Button[
                "x", 
                todos = DeleteCases[todos, #],
                ImageSize -> Small, Appearance -> "Palette"
              ]},
              Alignment -> {Left}
            ], 
            ImageSize -> {300, 40}
          ] &, 
          todos
        ]
      ]
    ]
  }]]

The code here probably doesn't need much explanation. One thing to notice here is that, as it is rather characteristic for UI code in Mathematica, the state (model) is mixed with the appearance (view). One can separate them, but this is some extra work.

Now, the Angular code: the plunker is here, but I will also provide the code in the post (you will need also the styles for it to display as intended, see plunker):

<!doctype html>
<html>
<head>
   <title>AngularJS • TodoMVC</title>
   <link rel="stylesheet" href="styles.css">
</head>

<body ng-app="todomvc">

<todo-list></todo-list>

<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.0/angular.js"></script>

<script>
  var  todoListTemplate = `
    <section id="todoapp">
      <header id="header">
        <h1>todos</h1>
        <form id="todo-form" ng-submit="$ctrl.addTodo()">
          <input 
            id="new-todo" 
            placeholder="What needs to be done?"
            ng-model="$ctrl.newTodo" 
            autofocus>
        </form>
      </header>
      <section id="main" ng-if="$ctrl.todos.length">
        <ul id="todo-list">
          <todo-item 
             ng-repeat="todo in $ctrl.todos" 
             item="todo" 
             remove="$ctrl.removeTodo(todo)"
          ></todo-item>
        </ul>
      </section>
    </section>
  `;

  var  todoItemTemplate = `
    <li>
      <div class="view">
        <label>{{$ctrl.todo.title}}</label>
        <button 
           class="destroy" 
           ng-click="$ctrl.remove({todo:todo})"
        ></button>
      </div>
    </li>`;

  angular.module('todomvc', [])
    .component('todoList', {
      template: todoListTemplate,
      controller: function() {
        this.todos = [];
        this.newTodo = '';

        this.addTodo = () => {
          var newTodo = {
            title: this.newTodo.trim()
          };

          if (newTodo.title) {
            this.todos.push(newTodo);
            this.newTodo = '';
          }
        };

        this.removeTodo = (todo) => {
          this.todos.splice(this.todos.indexOf(todo), 1);
        };
      }
    })
    .component('todoItem', {
      bindings: {
        todo: '<item',
        remove: '&'
      },
      template: todoItemTemplate
    });
</script>
</body>
</html>

Mathematica vs Angular.js: similarities and differences

If you look at the js / html code and Mathematica code, they are not very dissimilar. You can very approximately view Angular's component controllers as analogs of Mathematica's DynamicModule constructs. Data bindings, which are made explicit in Angular, are implicit when we use Dynamic in Mathematica. One striking difference is that in Angular / js code, the view (html templates) is much more separated from the model (described by the js code, in particular variables todos and newTodo). The pure js code that actually is responsible for adding and removing todos, is almost as short in js as it is in Mathematica. What you can see also is that the angular code tends to be more structured, with components well separated. It is possible to do the same in Mathematica, but it is not the default development mode and requires extra work and discipline.

You can also see what means are used for 2-way data binding:

  • In Angular, it is achieved, in particular, by input directives like ng-model, ng-click etc, which sync view (input fields etc) with the model. The other side of the sync is not immediately visible, but comes from the digest cycle.
  • In Mathematica, Dynamic itself is syncing both ways, which is rather elegant. Note that the sync between the view and the model is achieved by the second argument of Dynamic - which is a function that defaults to (expr=#)&. The controls like InputField[Dynamic[x]] are therefore directly analogous to Angular's ng-model directive, and serve exactly the same purpose. The other direction (sync between the model and the view) is invisible in Mathematica, just as it is in Angular.

In both cases, we de-facto have 2-way binding, which is what makes the actual code to implement UI components very succinct. The mechanisms behind this are of course different, but the way it feels to develop UI is actually rather similar. Of course, if we dig deeper, we will find many more differences (e.g. Angular has a nested scope structure and provides different encapsulation mechanism from Mathematica, etc.), but this wasn't my goal in this example.

Some additional notes

Mathematica's approach gains extra power from using the fact that the UI interface elements, the data and the code that manages it are all Mathematica expressions, written in a single symbolic language. This is in fact what allows one to use a single Dynamic construct for the same purposes where Angular and other js frameworks have to use a sort of DSL - simply because the UI (view) part and the model / controller parts are expressed in two different languages (HTML and js, respectively).

Both of the mentioned above Elm and Red languages seem to take somewhat similar approaches (to Mathematica) in the sense that they allow one to describe the UI, model and controllers in the same language, introducing into the language reactive primitives. For some other functional languages, such as OCaml and F#, there are web frameworks (Ocsigen for OCaml and WebSharper for F#), which use the same ideology, adding the reactive primitives and UI - building DSLs for these languages on a library level).

Another strong point for Mathematica is that, given that its UI elements are symbolic expressions (that are, in particular, already parsed), Mathematica's UI language has natural strong capabilities for templating and composition - something that is achieved by special template DSLs for js / HTML. I have a feeling that these capabilities are however under-appreciated and under-used in typical Mathematica UI development, and the main reason for that I think is that a typical Mathematica UI code mixes model and view too strongly, making UI components stateful, which flies in the face of easy composition. I don't view this as a fundamental problem though - surely there are ways to deal with that within the language, they just need to be explored more.

Conclusions

Mathematica's Dynamic - based UI construction approach seems to belong to a wide field of Reactive Programming, which is a generic term for UI programming approaches which attempt to automate propagation of state changes and treat event-handling declaratively.

From the user experience viewpoint, building Mathematica UI using Dynamic feels a lot like building web UI using a framework like Angular.js (to me at least). Both are based on the so-called 2-way data binding model, and both expose high-level interface and almost completely hide the internal engine used to propagate changes. To make these similarities more explicit and also discuss some of the differences, we considered a simple example of a TodoMVC app.

There are certain features that make Mathematica's approach stand out, and add potentially very powerful capabilities - the fact that a single language is used for both UI and model / controller code, and the fact that this language is symbolic, homoiconic and well-suited for metaprogramming. My personal feeling is that these capabilities have not, however, been fully utilized yet, most probably because typical quickly written Mathematica UI code mixes views and model too much, which makes UI components stateful and hinders their composability. But this seems to be more a problem of how the language is currently used than a problem of the language itself. A systematic framework that would separate views, models and controllers, could help here. This is one place where perhaps some lessons could be learned from other languages / frameworks.

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