• Keine Ergebnisse gefunden

In this section, we present a formal calculus that precisely describes the dynamic and static semantics of dependent classes. This calculus is calledvcnto indicate that it gener-alizes the previous formalization of virtual classes invccalculus [EOC06] by introducing more dispatch dimensions.

The calculus is focused only on the core aspects of dependent classes: dynamic and static dispatch, as well as path-dependent types, allowing to relate variations of multiple objects. The core semantics of dependent classes is already complicated enough, thus it was important to keep the calculus as small as possible. Therefore, like Featherweight Java [IPW99], we define the calculus in a functional style to avoid the complexity as-sociated with mutable state and its typing. vcn also follows the encoding of methods by classes introduced in vc [EOC06]. This further simplifies the calculus by reusing class instantiation expressions and class dispatch for method calls and method dispatch, respectively.

The resulting calculus is much smaller than theDepJ, which we used for examples. In Sec. 5.2.1 we present the syntax of the calculus and explain its differences toDepJ. The operational semantics of the calculus is defined in the “small-step” style. We managed to reduce the operational semantics to two computation rules and two congruence rules, which are presented in Sec. 5.2.2.

The major complexity of the calculus lies in its type system, the presentation of which is divided in four sections. Sec. 5.2.3 defines the type equivence relation, which is based on normalization of terms in dependent types. Sec. 5.2.4 defines substitution relations for dependent types. Sec. 5.2.5 defines mutually recursive subtyping and matching relations,

Syntax:

P ::= D

D ::= C(f :t) :textendsC {e}

p, q ::= f

t, u ::= p | C(f :t) | v

e ::= this | e.f | new C(f =e) | v v ::= C(f =v)

C − class names f − field names Context:

Γ ::= C(f :t) | ∅

Figure 5.1: Syntax

which are pivotal to the semantics of dependent classes. Finally, Sec. 5.2.6 defines expression typing and remaining type-checking rules.

In Sec. 5.2.7 we present the properties of the calculus. We state the soundness theo-rem and the major lemmas, outlining more specific properties of the relations of the calculus supporting the soundness. The section does not include the complete proof of soundness and only gives a reference to the automatically checked proof definitions using Isabelle/HOL. In that subsection, we also demonstrate decidability of the calculus and formulate the completeness property for path normalization.

The vcn calculus is deliberately left open for variations on specific dispatch strategies.

Therefore, in Sec. 5.2.8 we discuss different strategies for selecting the most specific matching declarations, and explain how the calculus could be specialized to support them.

5.2.1 Syntax

The syntax of vcn is defined on the left-hand side of Fig. 5.1. We have made a few design decisions to keep the calculus simple in order to focus just on the core semantics of dependent classes, and to ease the soundness proofs. For the informal explanation of the concepts and the examples in Chapter 4 we used the syntax of DepJlanguage that is close to the syntax of Java. Besides, we used various language features that are not interesting from a semantics perspective, but are useful for practical programming. For example, various predefined types, such asint,double,String, and operations on them are not available in the formal calculus. In the following, we explain the formal syntax of vcn and its differences toDepJ.

A program P in vcn consists of multiple class declarations. A class declaration, D, starts with a class name (note that the class keyword is skipped), followed by a list of field declarations and the return type of the class constructor. The list of declared fields

also specifies the list of constructor parameters. A class can have an arbitrary number of super-classes specified in itsextendsclause. The body of a class declaration contains its constructor expression, which is called when the class is instantiated.

There is no special syntactical category to encode methods. As usual in formal accounts of virtual classes [OCRZ03, EOC06], we use the syntax of class declarations to encode both classes and methods. A method declaration is encoded in vcn by a class decla-ration: Method parameters are encoded as constructor parameters, the return type as the constructor return type and the implementation as the constructor expression. For

“normal” classes, i.e., those that do not encode methods, we assume the expressionthis to be the default constructor body, i.e., the constructor simply returns the constructed object. The default return type is the empty path– the path pointing tothis. Method calls are encoded as constructor calls. Multimethods can hence be encoded by using class declarations as methods.

In the calculus all declarations are at the top level, which means that it is not possible to nest methods within class declarations. However, the nested style can be easily translated to the parametric style as was explained in Sec. 4.3.1.

Apath, referred to byporq, is a sequence of fields; it refers to the object that is reached by navigating over the fields in the sequence starting from this. As a special case, the empty pathrefers tothis.

A type, referred to byt or u, can be a class type C(f :t), a pathp, or a value v. The class type C(f : t) represents all objects of C and its subclasses, whose fields fi have values compatible with the respective types ti. The only instance of a path type is the object referenced by the path. Avalue type,v, has the valuev as its only member.

Types that contain paths are called relative types, as they are defined only relative to some object (referred to by this). On the contrary, absolute types are combina-tions of class and value types. For instance, Vector(s: v1.s) is a relative type, whereas Vector(s: 3DSpace) is an absolute type.

Most type relations of the calculus are defined relative to a typing context Γ, which is either empty (∅) or defines the type of this. Relative types make sense only in a non-empty context, while an empty context can be used with absolute types. During static type checking (program well-formedness), the context will always be non-empty, whereas during runtime checking (typing intermediate expressions during evaluation) the expressionthisdoes not occur (it is replaced by a value) and the context will always be empty.

The calculus requires that in a class type the types of all fields that are available in this class are specified (this requirement is enforced in the well-formedness rules). In the informal language we allow omitting some of the field type annotations. In this