With release v0.5.0 comes the first Alpha version of the Perspectives Distributed Runtime. Below is a video demonstrating how two installations of the program connect for the first time and then are able to exchange information.
What this demonstrates
The functionality shown in the video is deceptively simple. It seems to boil down to logging in and a simple screen that allows one to enter a text message that is echoed on another user’s screen. Nevertheless, all mechanisms that make up the PDR are involved. Below we list them in some detail.
Accounts / the set-up
Please note that the video shows two separate installations of the PDR, even while they run on a single computer. They might as well have been on two different machines; there is no connection (yet) between them at the outset. So when we write ‘two accounts’, this does not mean there is some server that registers two users.
On startup, we see that a single model (or App) is installed: the system App itself (called, in Dutch, “Mijn Systeem” – My System). This is the bare minimum for the PDR to be able to run. This shows that:
- model source texts (see an example below) can be compiled
- compiled models can be used by the PDR.
A Graphical User Interface
Next, the screens demonstrate that a graphical user interface is in place. It consists of
- a screen to log in;
- a starting screen that lists available top level contexts;
- a mechanism to navigate to another context (by clicking a link that represents a context, the GUI asks the PDR what role the user plays in that context. It (the GUI) then fetches the screen that visualises the perspective of that user on that context. Screens belong to models and are packaged together with them;
- a library of React data containers that the screen builder constructs his screens on;
- a proxy library that connects the screen process to the PDR process.
Repository, local models, on-the-fly model loading
The PDR supports on-the-fly model loading. Whenever it encounters a role or context instance that has an unknown type and it needs to reflect on that type, it fetches the model that defines the type from the repository (the type name is built from the model name). Please note that the repository is some webserver that just holds models. It does not store user data! With ‘fetching the model’ we mean that a PDR downloads it from the repository and saves it locally. From then on, it is always used from that local storage.
Right now we just handle a single repository: that will be extended in the near future. Repositories are really like App Stores. Another thing to be added is a dialog that asks the user for his consent: does he agree to download the model and start using it?
We actually see two demonstrations of this on-the-fly loading:
- when the user drags the card representing model:SimpleChat in the upper window to the column of models in use (thereby indicating he wants to use that model)
- when the (other) user drops the invitation in the lower window.
The first example might be a little surprising. After all, the user explicitly indicates that he wants to use SimpleChat, so why would this be ‘on the fly’ loading? Fact is, there is no explicit mechanism behind that drag and drop that sets in motion a procedure to download a model. By dropping the model:SimpleChat card, the user constructs a binding with the (role that represents) the Simple Chat context. The PDR needs the model to see if that binding is allowed and loads it as a side effect.
Creating bindings is a very elementary and very important operation in Perspectives. It allows us to construct large structures from simple elements.
Roles and Contexts: serialisation to JSON
All Perspectives data come in the form of contexts and roles. These are stored in a database in some propriety format (actually, a JSON serialisation of Purescript datastructures). However, we have defined a somewhat readable and compact JSON representation that can be used by programmers to have the PDR create new contexts.
This is actually what happens when the user clicks the ‘Start a chat’ button in the SimpleChat App. A JSON representation, constructed in the GUI, is sent to the PDR and deserialised.
Conversely, when the user later drags an invitation from his screen, to send it to someone with whom he is not yet connected on Perspectives, internally represented contexts and roles are serialised as JSON and made available as a file. The receiving PDR then deserialises it (just like when the ‘Start a chat’ button was clicked).
Roles and Contexts: serialisation as Deltas
As soon as two users are connected on Perspectives, their PDR installations exchange information in another form. Each relevant change made by user A will be sent as a delta to user B. Actually, deltas come in packages called transactions. These transactions – being JSON documents – are sent through some mechanism between two PDR installations. Currently, we use a Couchdb database dedicated to the connection between two users – a channel database. We will likely replace this by another mechanism in the future, e.g. AMQP. The fact that the two users can actually chat, shows that transactions are exchanged.
A Perspectives model spells out what its users can see and do. However, we can define a bot for a user and so automate some of his work. This example rests on a number of bots. A prime example is the bot for the Inviter role of the context Invitation. As soon as the end user indicates he want to send an invitation, and as he has finished the message to be sent with it, a bot creates a channel database for him and a context to hold it and, later, the other user of the channel. Below is the relevant part of model:System.
External function interface
The Perspectives Language (PL) has many keywords and functions. However, there are potentially infinite many extensions. Instead of extending the language time and again, we’ve created an external function interface that allows us to quickly add functions. The bot example above shows how one such function is called.
An astute reader may have noticed that even while an invitation was dragged from the upper window and dropped on the lower window, the end result (after accepting the invitation in the lower window) is that a chat has been communicated.
This is no contradiction. The context type Chat is modelled with the Context type Invitation as an aspect. Aspects allow us to quickly mix in roles and their perspectives. It is an important abstraction mechanism in Perspectives. See the (simplified) definition of Chat below.
In other words, an instance of a Chat is also an instance of an Invitation. As Invitation is far more general than a Chat, it is part of model:System. Notice that we map specific Chat roles to specific Invitation roles. We need not map; we might just import the Invitation roles. However, in this situation, the mapping is quite natural.
A role ‘inherits’ the perspectives and bots of its aspects. Hence, the Initiator of the Chat has a bot working for him (as explained above).
Functional reactive pattern
As soon as one user enters a text in his Chat box, it appears on screen for the other user. Many mechanisms are at work here, but ‘the last mile’ in the receiving PDR installation is the functional reactive pattern. The GUI of InPlace asks the PDR what instances there are for a specific role type for a given context; it can also request property values for a role instance. Now, when the answer to such a question changes, some time later on, due to changes made by some other user for example, the PDR informs the GUI of this change. This is the functional reactive pattern.
In short: the information displayed on the screen always reflects the actual state kept by the PDR. The mechanism behind this depends on a form of dependency tracking.
Perhaps the most distinguishing feature of the PDR is the mechanism of synchronisation. Usually, clients of an application are kept in sync by storing all information in a single location (the server). Not so in Perspectives. Instead, for every change made by some user, the PDR computes the other users that now need an update. This computation is based on the model, that defines, for each user role, a perspective.
The problem is exacerbated by the fact that user roles may look outside their contexts into other contexts. In combination with the fact that, at any moment, not all contexts reside in computer memory, this calls for a special mechanism. In spirit it is similar to the technique behind rule based systems (the so-called RETE algorithm).
The demonstration video shows how, as soon as the second user accepts his role in the invitation, some information is sent back to the inviting user. Exactly what information follows from the model and the general computation mechanism.
We claim that the problem of figuring out of what goes to whom has been solved, for the entire class of programs expressible in the Perspectives Language.