9.2.4. Solutions

9.2.4.1. Recognizing versions

If we include version identifiers with type names, we can quickly establish what situation we have at hand, when a delta arrives and we cannot find a type name. On looking up a type name, we currently split it into a model name and a local type name. Including version numbers requires us to split the name into a third part, its version number, which is not a big deal.

We would immediately recognise a version mismatch. But we can do better. Compatibility over versions can be established per type, with each type recording the earliest (oldest) compatible version (this would need to become part of the model parsing and checking process). Upon recognising a model type mismatch, we can then establish whether the type in our model version is compatible with that of the incoming version (notice this may require us to retrieve a newer version).

Second, the problem of the wrong shape for an attribute value. We would immediately establish whether the problem exists, by checking if the incoming version of the property is compatible with our local version.

9.2.4.2. Unique model names

The issue of type name changes ties in with another, related potential problem and that concerns the uniqueness of model names. We need our model names to be both readable by modellers and to be unique - worldwide. That should either be solved by a global register (such as the DNS) or by GUIDs. Barring a global register, we must rely on GUIDs. As GUIDs are not readable, we must use a (local) name translation system that gives the modeller the illusion of uniqueness of readable names, while protecting them from name conflicts if they arise. We will equip a DomeinFile with both a readable and a unique name. The modeller can write his text in terms of the readable name: on parsing, the PDR substitutes the unique name. Now if a modeller wants to use two dependencies that have the same readable name, he must use a substitute in his text. The issue is: how to associate a substitute with a model? The association must be in the model text. The straightforward way would be to include the unique name in the text. For example:

use: sys for model:System
use: esys for model:System (<guid>) -- Electrical system modelling.

IDE support might assist in inserting the guid.

9.2.4.3. Handle type name changes

Modellers might change the name of a type from one version of the model to the next.

We check a dependent model, however, by parsing its source again, using the new DomeinFile as dependency. This will cause any reference to a renamed type to be thrown up as an error. An error that could be prevented, if only we knew how to substitute an old name for its new value!

So we need, as the result of parsing an adapted model text, a table that maps old names to new ones.

There appears to be no robust way of building such a table automatically. Instead, we offer the modeller a way to provide hints, so reference errors for dependent models can be avoided. A hint consists of the old name in square brackets immediately behind the new name. The parser builds those hints into a full table. Notice that this must handle changing namespaces, as well.

It should be noted that this is a solution for consecutive model versions only. Clearly, a name that changes in two successive versions, needs a different translation table for dependents that refer to different versions.

9.2.4.4. How to adapt a source file given a translation table

Given a table that maps, for a given dependency, the old names to new names, how can we adapt the source file to the new situation?

First, notice that references to types outside the model must be fully qualified. Such names come in two forms: expanded and prefixed.

Expanded names are easy to map to their new versions. Replacing them in the source file is just a matter of string replacement.

Prefixed names are more difficult. The main problem is that prefixes only hold for a given syntactical block. A modeller may use the same prefix as a substitute for different context names. If the source then contains the same local name, in different blocks, with the same prefix (but another mapping) we can no longer substitute globally. Luckily, we can detect that situation and warn the modeller that he must change his source before dependency name substitution can be carried out.

9.2.4.5. Unique names to protect instance data

Were we to substitute internal names for model type names that would persist through model versions, we could protect references in instances to types to those changes. Succinctly: instead of using the readable name as the type reference in instances, we would use the unchanging internal name.

This is very important. Without this facility, a model type name change must be followed by type reference changes in all instances of that type.

We can achieve this by including in the DomeinFile a translation table from readable names to internal names. Notice that this is a different table from the one that maps old names to new names. On parsing the source text again, we look up each readable name in this table and use its internal substitution in the data structures we’re building.

By running each name through the old-new table, we can find the internal name for a new name.

9.2.4.6. A diff function for model source files

By comparing DomeinFiles, we can construct a structure of data that details the differences between a model’s types. This structure could be encoded as JSON and we could generate a readable report from that, to be consulted through the MyContexts GUI.

We can put this diff structure to good use by providing hints for the modeller that can be shown in the IDE. Particularly, we might draw his attention to references to type names he failed to update after renaming the type (e.g. a property name in a view). We can do this because the DomeinFile refers using the internal name and we can look up the new readable name and compare it with the name in the text.

Another service is that we can detect a new name in a particular namespace, notice that another name has disappeared, and suggest that the modeller may have forgotten to include a renaming hint for the parser. E.g. when a role with local name MyRole may have changed to SomeRole, the modeller should have included the name change in the text (SomeRole [MyRole]). We can provide the following hint, in the form of a question: "Did you rename MyRole to SomeRole?" Obviously these hints are not infallible.