• Keine Ergebnisse gefunden

packagebanking;

importbanking.ATM<statemachine.SM2Java>asATMJ;

public classATMTest { public voidtest() {

ATMJ machine=newATMJ();

machine.step(machine.event_DoWithdraw());

machine.step(machine.event_PinOK());

machine.step(machine.event_MoneyTaken());

machine.step(machine.event_CardTaken());

assertmachine.currentState()==machine.state_Init();

} }

Figure 6.4: ATMTest depends on a generated Java implementation of ATM.

the client of a generated model: We writeimportModel<Trans>asIdentto declare a dependency on the result of applyingTranstoModel. A client thus does not depend on any external modeling artifacts except for the ones explicitly declared with import statements. In conventional MDD frameworks, the generation of ATMJwould be specified in a build script, andATMTest would importATMJby name. JProMo avoids such fragile dependencies and enables modular reasoning.

The state-machine case study illustrates the spirit of model-oriented program-ming: We use model-based domain abstraction where useful, but write pure application code in Java where appropriate. In model-oriented programming, model-driven and code-driven development are fully integrated and connected through the unifying library concept. Due to the uniform handling of depen-dencies and transformation application by imports, communication integrity is maintained and all concepts are applicable across metalevels. Our formalization will illustrate how exactly this works and why we can in fact guarantee these properties.

6.4 Formalization

Syntax:

n ∈ Name

m::= (n=iin e) modules have imports and a body i::=n|ihii import by name, import transformed e::=. . . module body left abstract

Semantic domains:

D=M×(B+T+{•})

B=. . . base semantics left abstract

M=m×Γ models close over the dependencies of a module T=M→D transformations map models to semantic artifacts Γ =Name→D environments

Figure 6.5: Syntax and semantic domains of model-oriented programming.

our implementation and to describe model-oriented programming in its full generality, we specify an abstract core of model-oriented programming that illustrates the meaning of models, transformations, and imports, and is sufficient to state and prove communication integrity and separate compilation.

Figure 6.5 shows the syntax and semantic domains of our abstract core language for model-oriented programming. Programs are organized in modules m. A module consists of a sequence2 of namesnbound to a sequence of module imports i in the module’s body e. For instance, the import statement from Figure 6.4 would be written asATMJ=ATM<SM2Java>. An import references another module either by name n, or by transformation i1hi2i of a model i1

with a transformation i2. The syntax of a module bodyeis not of relevance for the formal development; we leave it unspecified. In JProMo,e includes Java programs, transformations, and grammars.

We specify the semantics of our core language for model-oriented programming as a denotational semantics, that is, by a compositional mapping of each program to a mathematical object of the corresponding semantic domain [Sto77]. Our semantics is acompile-timesemantics; the dynamic semantics of the final program is not in the scope of our formalization.

The semantic domain of modules isD: Each module is mapped to a pair com-posed of other semantic domains. Bstands for the semantic domain of compiled

2We use the standard notation of writingxfor a sequencex1. . . xn

application code, which we leave abstract in the formalization. For JProMo,B would correspond to the domain of Java class files. M stands for the semantic domain of models, which consist of a syntactic module representation and an environment that provides mappings for the dependencies of the module. In analogy with function closures, we say that a model closes over the dependencies of a module. Transformations T are functions that map models to semantic artifacts. Since a transformation may fail, we allow the error value⊥as a result of a transformation. Coming back to the semantic domain of modulesD, the first component denotes the model corresponding to the closed module and is always present, whereas the second component depends on whether the module describes application code, a transformation, or a model. In the latter case, we do not require a second representation of the model and use the unit element•.

The design of the semantic domains already illustrates how we realize unifor-mity. First, every semantic artifact fromDcan be reified as a model to serve as the input of a model transformation. In addition to models, this includes regular application code such as a Java class in JProMo. We realize this by accompanying each semantic artifact with an explicit model representation.

Second, a model transformation fromTcan produce any semantic artifact. In particular, we support higher-order transformations, that is, transformations producing other transformations. Since transformations also need to produce a transformed model (the first component ofD), it is also possible to compose transformations sequentially.

We provide the denotation semantics of our core language in Figure 6.6.

Functionsem-mod defines the semantics of modules. It accepts a module and an environment and yields an element ofD. sem-mod first resolves each import ix∈iof the module using functionresolve. For a named importi=n, function resolve looks up the name in the environment. For an applicationi1hi2i, the function resolves i1 and i2, and, if i2 resolves to a transformation, applies this transformation to the model reification ofi1. sem-mod uses the resolved importsdto construct an environmentσthat binds the imported artifacts to the namesn. This environment only contains artifacts explicitly referenced through imports, i.e., the domain ofσ is n. sem-mod uses σto evaluate the body of the module withsem-exp, which we leave unspecified. If the evaluation of any of the imports or the module body fails (yielding⊥),sem-mod yields⊥itself.

Otherwise, sem-mod yields a pair consisting of the module’s closure and the result of evaluating the module body.

We deliberately designed the semantics in a way that achievescommunication integrity. This required two design choices. First, we chose a representation

6.4 Formalization

Semantics:

sem-mod : m×Γ→D

sem-mod(n=iine, ρ) =

⊥, if⊥ ∈d or body=⊥ (m,body), otherwise

where dx∈d=resolve(ix, ρ)forix∈i σ =mkenv(n, d)

body=sem-exp(e, σ) m = (n=iine, σ) sem-exp : e×Γ→(B+T+{•,⊥}) sem-exp(e, ρ) =. . .

resolve : i×Γ→D

resolve(i, ρ) =













ρ(n), ifi=n d2(m1),ifi=i1hi2i

and(m1, d1) =resolve(i1, ρ) and(m2, d2) =resolve(i2, ρ) andd2∈T

⊥, otherwise

mkenv : n×D→Γ mkenv(ε, ε) =λn.⊥ mkenv(n·n, d·d) =λn0.

d, ifn=n0 mkenv(n, d)(n0), otherwise

Figure 6.6: Denotational semantics of model-oriented programming.

of models that is closed over external dependencies. All dependencies of the encapsulated module can be resolved within the accompanying environment.

This is similar to lexical scoping of functions, which is typically achieved by a closure consisting of the function definition and its lexical environment. Second, in contrast to other MDD frameworks, we require transformations to produce semantic artifacts instead of syntactic artifacts. Typically, a model-oriented-programming transformation achieves this by first applying a syntactic rewriting and then calling the compiler (functionsem-mod) on the resulting artifact. How-ever, in the call tosem-mod, the transformation has to provide an environment,

too. Since the transformation does not receive any input apart from the original model, this environment can only map to artifacts available within the input model or the transformation itself.

Therefore, communication integrity holds: It is not possible for a transforma-tion to inject implicit communicatransforma-tion channels between modules. We formalize this in the following. First, we define functiondeps-mod, which computes the explicit dependencies of a module, which are locally declared with imports:

deps-mod : m→2Name deps-mod(n=iin e) =S

ix∈i deps-imp(ix) deps-imp(n) ={n}

deps-imp(i1hi2i) =deps-imp(i1)∪deps-imp(i2)

Communication integrity then states that the semantics of a module only depends on these explicitly declared dependencies.

Lemma 1. For all imports i and environments ρ and σ, if ρ|deps-imp(i) = σ|deps-imp(i) then resolve(i, ρ) =resolve(i, σ).

Proof. By structural induction oni. The base casei=nfollows fromρ|deps-imp(i)= σ|deps-imp(i), which entails ρ(n) =σ(n). The step case follows directly using the induction hypothesis twice.

Theorem 1(Communication integrity). For all modulesmand environments ρandσ, ifρ|deps-mod(m)=σ|deps-mod(m) then sem-mod(m, ρ) =sem-mod(m, σ).

Proof. By Lemma 1, eachdx∈dfrom the definition ofsem-mod evaluates to the same value underρandσ. Since the body of the module is evaluated under the constructed environment mkenv(n, d), the result of sem-mod is the same underρandσ, independent of the definition ofsem-exp.

As direct consequence of communication integrity, we get separate compilation:

A module m can be compiled in separation of any other module n if m is independent ofn.

Theorem 2(Separate compilation). For all modulesm, environmentsρ, and namesn, ifn6∈deps-mod(m)then sem-mod(m, ρ) =sem-mod(m, ρ|dom(ρ)\{n}).

Proof. By Theorem 1 withσ=ρ|dom(ρ)\{n}.