Motivation describes the motivation for our project. There, we recognise that there are many different views of systems structure, expressed in many different languages, and that these different views need to be related together. However, our experiences, over fifty years, tells us that the languages get in the way of this "relating together". They make rigid distinctions between things that are not fundamentally different, e.g. programs and data, procedures and interfaces, types and instances, processes and transactions, etc. Worse still, the strong distinctions made by each language are inconsistent with the strong distinctions made by other languages. We therefore want to get away from these distinctions and start from an extremely simple semantics.
We have a very simple modelling style that matches our motivation and enables us to relate together the many interacting views of system structure that were referred to above. The primitive semantics of this modelling style has just one type of object - a system, and one type of relationship connecting such objects - a role of a system as a component in another system. We show that this modelling style can cope with the full range of mathematical and business problems, and can be related to other modelling styles.
When people talk about a particular system, such as Sainsburys, their views of the system, and hence of its component structure, may be very different. One person may see it as just a set of shops and staff; another may see it including its very complex supply chain; a third may see it as just a financial institution with money flowing between its components. All of these views can be represented in our modelling style as different systems, possibly sharing components, and ideally contained, as components, within one large system that encompasses all possible views of Sainsburys.
Below, we describe our modelling style in terms of a multi-dimensional space. Only the first three dimensions of this space are built into our modelling style. However, they provide a flexible base for the other dimensions; the other dimensions are essential for the effective use of our modelling style.
The following three dimensions are built into our modelling style and its support; they are described in Basic Concepts.
We see all systems, which are of current interest, as being modelled in a graph C. A node in this graph represents a system; a line indicates that the system at the bottom of the line is a component of the system at the top and has a role within that system; the role is identified by another system. The union of all versions of C, over all time, is an infinite graph S. These ideas are described in more detail in Basic Concepts. Graph C provides the containment dimension of our multi-dimensional space.
In the Evolution Dimension, one version of C evolves into another (we characterise this as the moving of a spot-light across a canvas provided by S). Some systems within C have "life", in the sense that they can evolve themselves, and thereby evolve C. One very primitive "living" system provides the bind operation (described in Basic Concepts); this operation makes the minimal transformation of C - it replaces just one line in C. More complex live operations can be built from this one minimal operation (as demonstrated in Programming Manual). Problems ranging from basic mathematics to high level business problems can be modelled using such operations (as shown with Lambda Expressions and Change of Government). An interpreter can interpret a sequence of bind operations and these bind operations can change the interpreter’s subsequent sequence. Interpreters can spawn additional interpreters, each interpreting its own sequence of bind operations. Interpreters, operating concurrently, can modify each other’s sequences of binds, thereby affecting each other's behaviour. The spawned interpreters can include aliens (that appear to be contained within C, but actually are outside of it); these aliens enable interfacing to the humans and the hardware and software systems surrounding C, thus enabling C to evolve in tandem with the real world.
The Representation Dimension needs a fairly broad definition of the term “representation”. The implementation of our original interpreter treated the graph C as a "representation" of a C# structure (and thereby treated the C# structure as the "reification" of the graph C); when it interpreted the evolution of one version of C into another, it also evolved one version of its C# structure into another. Similarly, high level language code provides a representation of machine code; an interpreter of a high level language program models the evolution of the high level language program (and its workspace) by concurrently evolving the equivalent machine code program (and its workspace). A hardware interpreter of machine code models the evolution of the machine code program (and its workspace) by concurrently evolving the firmware (and its workspace). If these examples are all captured in our graph C, then, in each case, an interpreter operates by mapping the evolution, within C, of one system (the representation) into the evolution, within C, of another system (the reification). The reification (the represented system) may in its turn be a representation of a still lower level system and so on ad-infinitum. In fact, this dimension does not go down, ad-infinitum, within C, as it bottoms-out in something like our C# implementation. It does not go up, ad-infinitum, within C, because it tops-out in the human-interface (as shown in Human-Interface).
The following dimensions are not built into our modelling style but built on it (though they are needed for a fully useful modelling style). They could take many forms. There is clearly a danger, that their provision could, if not carefully considered, recreate the problems we were motivated to eliminate, recreating the clashing distinctions of existing languages.
We described, above, how our interpreter interprets a program built from sequences of primitive bind operations. We implied, above, that, as our interpreter is a system like any other, it can be held as a living system in C, with its own program built from primitive bind operations; these bind operations are interpreted by a "lower level" interpreter and this interpreter looks very like our interpreter; this lower level interpreter, in turn, has its own program interpreted by another interpreter, and so on ad infinitum. In practice, we have to bottom-out this infinite hierarchy of interpreters, by providing an interpreter that is outside of C, e.g. an interpreter with a program written in C# (because our basic model is so simple this interpreter is very simple - just a page of C#).
Our description of the bind operation hints at another dimension. The bind operation is a system that changes a role in another system; the other system may itself be a bind operation. The bind operation, that is making the change, is operating at a higher level of functionality or control than the bind operation that it is changing. The first bind operation is the evolver for its evolvee, the second bind operation. This is the minimal example of an evolver-evolvee relationship between systems, with the evolver and evolvee each being a minimal bind operation. Other evolver-evolvee relationships require much more complex systems as evolver and evolvee. As we implied in an earlier section, the "living" systems in graph C effectively contain programs (built from bind operations) that drive the evolution of C. Hence, when we talk of representation and reification, we are talking of representation and reification of programs as well as data. Furthermore, we could be talking of representation and reification of higher order programs capable of changing programs. Hence changing a representation may result in changing a program in the reification and thus the behaviour of the reification. This hierarchy of control may span many levels.
In the section on the Evolution Dimension we referred to "more complex live operations". We were saying, there, that powerful operations may be built from weaker operations and ultimately from our primitive bind operation. This hints at how our modelling method might be used to develop models of very complex systems. We have begun to demonstrate this in Programming Manual, Lambda Expressions and Change of Government. In our Change of Government example we treated change of government as one complex operation and gave it an expansion in terms of a kissing hands operation (that modelled the deceptively simple ceremony where the British Monarch passes power to a new Prime Minister). The model we provided was very simplistic; it showed that power passed from the old prime minister to the monarch and then onto the new prime minister, but did not spell out the full complexity of that power (controlling the evolution of the country) and the change in the way it is used (changing the direction of the evolution, as in 1945 and 1979).
We need to consider, in more detail, how our modelling style relates representations and reifications of systems.
In describing the Representation Dimension, we gave a very one-directional view of the relationship between reification and representation; there we considered the evolution of the representation as being interpreted in terms of the evolution of its reification. If we consider the real world, as a reification, and C, as its representation, we see that the relationship can be bi-directional; evolution of either reification or representation needs to be correlated with evolution of the other; this implies correlation channels between reification and representation with an interpretation capability at each end of each channel. We also realise that each correlation channel is only correlating a restricted portion of the real world and C; the portions need to be separated from the wholes (separation of concerns) before the correlation and integrated back into the wholes (integration of concerns) afterwards. The mechanisms used in the correlation channels include interpretation as discussed above; however they also include compilation and editing by humans. The picture, presented in this section, is equally applicable if either both, or one, or neither of representation and reification are held entirely within C.
In the above, we have consistently talked of interpretation of representations (of those contained in C, as well as those outside of C, e.g. high level language and machine code representations). However, with high level languages, we do, normally, expect compilation rather than interpretation; we expect high level language to be compiled into its machine code reification and expect the machine code to be interpreted. On the other hand, there are occasions when we need to consider the detailed mapping between the interpretations of the high level language and machine code, e.g. when we want to debug and validate the use of the high level language; this may require many of the mechanisms needed for interpretation. In addition, a very large system is never fully compiled; its component programs may be compiled, but the binding together of these components must be done interpretively. Hence for a large system, we are talking about a mixture of interpretation and compilation - the interpretive binding together of pre-compiled components.
Consider our minimal interpreter; even though it is merely interpreting a sequence of minimal bind operations, there are a number of possible variations in its mode of operation. For each bind operation, the interpreter is given a representation of the bind operation; the end result of the interpretation is a new line in C. The parameters (components) of the bind operation, have to, in some way, define the line that is to be created in C. In order for this definition to be unique, the parameters must identify, for the line, the triple of containing-system, role, and contained-system. The bind operation could be totally self-contained, containing all of the information required to define the line; alternatively it could partially or even totally rely on contextual information, built up by previous bind operations, and retained by the interpreter. Reuse of programs (built out of sequences of bind operations), in different contexts, is a major motivation for a contextual approach. It is clearly difficult to reuse a program if its constituent bind operations contain all of their context; separating out the context makes reuse possible. We further explore our range of options on context and reuse in Basic Concepts and Programming Manual.
We could adopt evaluation strategies at one of two levels, or both - firstly an evaluation strategy for our minimal interpreter - secondly evaluation strategies for applications interpreted by that interpreter. Our minimal interpreter currently follows an eager-evaluation approach to interpretation; it insists on fully interpreting each bind operation in its sequence of binds before it proceeds to the next one; it could adopt a lazy-evaluation approach; in this case, it would not bother to create the new line in the reification until another bind operation required that line; there seems little point in doing this. Evaluation strategies for applications interpreted by the interpreter are much more interesting. We show in Lambda Expressions how lambda expressions can be mapped onto sequences of bind operations; this mapping could adopt a lazy or eager approach to evaluation. In Change Government we model the full power of government being passed to the prime minister in the kissing-hands ceremony; however, in reality, the implementation of this transfer of power is both eager and lazy; the civil service prepares for the transfer well in advance; on the other hand many parts of the civil service carry on unaffected until the new government makes its impact. If we modelled hardware pipelining in our modelling style we would also have a mixture of eager and lazy evaluation, eager when the hardware goes down both branches of a if-then-else operation, but lazy when it delays evaluating values of variables until they are required. The change of government example can be viewed in a more general way; each bind-operation effectively copies a system from one context (role in a containing system) to another; the component structure of the copied system may be changed at the same time, or before, or after or a mixture of these. Pipe-lining in hardware could give another rich example of evaluation strategies.
In the above, we effectively talked about a "representation of" relationship between two systems and the dual "reification of" relationship going in the opposite direction, and we implied that it was obvious in which directions these relationships went. However, if you consider a high level language program as a representation, it is not even obvious what it represents; for instance, a payroll program, written in a high level language, could be considered as a representation of the payroll process in the real world; on the other hand, it could be seen as a representation of the computer system that realises the payroll process; in other words, it can be seen as facing in both directions, representing the "reality" of the payroll process but also representing the "reality" of the computer systems. Furthermore, the payroll process might be described in some specification document; then the high level program could be seen as a reification of this specification. Despite these ambiguities, we do know that, in all cases, a representation and its reification need to evolve in tandem with each other.
We presented the Representation and Abstraction Dimensions as being quite distinct. However, they may use the same mechansisms and probably only differ in their motivation.
In the Evolution dimension we identified one primitive operation (bind) from which all other operations could be built; it would be nice if there existed a primitive mapping in the Representation Dimension from which all other mappings could be built. For our minimalist interpreter (interpreting a sequence of binds) this is possible, as the interpreter can only map sequences of binds to sequences of binds; however, the strategy for doing this can vary in many ways, including eager and lazy evaluation. We have shown that a wide range of programs can ultimately be transformed into sequences of our bind operations, and this presumably applies to high level language and machine code instructions; if this is the case then most interpreters can operate by mapping sequences of binds to sequences of binds.