• Keine Ergebnisse gefunden

Object Tree – A Data Model for Modelware Lenses

For adaptingFocal, we first have to look at its data model – edge-labeled trees – and how it can be adapted to a modelware setting. We therefore take the characteristic properties of the object-oriented modelware space into account but try to stay as close as possible to the semantics ofFocalin order to be able to reuse many of its lenses and combinators.

An object is a triple of a (1) unique identity by which it can be referenced, (2) a state, and (3) the implementing class defining valid operations on that object (Szyperski, 1999).

The state of an object is defined by the values of a fixed number of fields. In a Java-based context, fields have a unique name and a static type. Fields containing multiple values can be expressed as a homogeneously typed collection, such as an indexed list or a key-value map.

Thus, if we want to model the lens synchronization example from 5.3 in an object-oriented fashion, we could come up with an object structure as presented in the UML object diagram in Fig. 5.5. By comparing this with the edge-labeled tree from the original example, we can infer in what way the data model needs to be adapted. In the following three subsections, we explain the main differences, which are, in short, distinction between meta- and instance-level-data, non-containment references, and order. Afterwards, we define our data model, which we callobject tree, and present a type hierarchy for it.

5.2. Object Tree – A Data Model for Modelware Lenses 111

Figure 5.5: UML object diagram of an object-oriented version of the example from Fig. 5.3 5.2.1 Meta-Data vs. Instance-Data

First, in the edge-labeled tree, labels are used to access the children of a tree node. The counterparts in object-orientation are either class field names (or the names of public getter methods, respectively) or the index by which one can access a specific element in a homogeneously typed list (or the key to access a value in a key-value map, respectively).

Whereas data in the edge-labeled tree is stored as labels – e.g., the phone number in the example – we cannot save data as a field name in Java or Scala. This reveals one of the key differences between the original data model and the required one: With the edge-labeled tree, we have no meta-layer but only an instance layer. Both meta-information, such as the description of the content of a field, and value information is mixed – both

“phone” and “3334444” are labels. So, what is always a label in the edge-labeled tree, is in object-oriented terms sometimes meta-information and sometimes value-information.

This means, we need both lenses that work on the meta-level and lenses that work on the instance level. For instance, there cannot be just one fork combinator as in Focal.

We need onefork which splits the fields of an object into two sets based on the statically available meta-level field names, and one fork which splits the content of a collection based on value-information available only at runtime, e.g., based on the keys of a key-value map. In our data model, the distinction between meta- and instance-level data is reflected by every node having to refer to its meta-information by a type annotation. In contrast to the lenses in Focal, lenses designed for this data model are, in general, two-level transformations (Cunha et al., 2006): They transform the schema at the meta-level and, at runtime, transform instances at the value-level accordingly.

5.2.2 Non-Containment References and Leaf Representation

The next difference is that objects can reference other objects which are not considered their children, i.e., they can have non-containment references – object structures and models, in general, are graphs. However, as we explained in Sec. 2.3.1 Java-based mod-eling frameworks such as EMF, practically enforce a spanning containment tree within

112 Chapter 5. A Compositional Language for Bidirectional Model Transformation a model’s object graph. This constraint has been shown to be useful for graph traversal and persistency management. We include this constraint in our data model to allow the pragmatic adaption ofFocalto the modelware setting. We consider a model as a contain-ment tree with occasional non-containcontain-ment references. In this tree of objects, values can actually be saved only as leafs, that is, as non-reference attribute values. In contrast, in the edge-labeled tree, data can also be stored as labels of nodes. In our data model, leafs are therefore not represented by normal tree nodes with an empty children lists but by special value-holding leaf items with no children list. This explains why in the example object structure above, value"Pat" has become a leaf whereas it has been a node in the edge-labeled tree shown in Fig. 5.3.

5.2.3 Ordered Children Lists

Finally, the children of a tree node in an edge-labeled tree are represented by a set of labels, i.e., they are unordered and without duplicates. Now, as we defined field names or collection indices/keys, respectively, as the counterparts to labels for accessing child ele-ments, the uniqueness for children still holds true: indices or keys are unique by definition and field names in Java or Scala are also required to be unique in one class. Concerning order, the situation is more diverse: indices are obviously ordered but class fields and dictionary keys are generally considered unordered. However, EMF for instance, repre-sents the children of a containment tree node as an ordered list for XML persistence reasons. Furthermore, the fields of Scala case classes coincide with the argument list of the class’ constructor, which is also ordered. Thus, for uniformity, we define the chil-dren of a node to be an ordered list without duplicates and define the order of fields to be alphabetical. This means that in our data model an edge-label becomes an index of this contained-children list. If the containing node is not a collection, an index can be mapped to a field name using information from the node’s type annotation. Note that the uniqueness constraint only applies to the labels, i.e., to the list indices which are by definition unique, and not to what they refer to, i.e., the actual children.

5.2.4 A Type Hierarchy For Object Trees

Summarizing, we call this data model, which we designed as a pragmatic adaptation of an edge-labeled tree to an object-oriented modelware context, an object tree.

Definition 5.1 (object tree). An object tree T = ht,id,[v|l]i has a type-annotation t, a unique identity id, and contains either a single valuev or an ordered list l referring to either a fixed number of subtrees (the fields) or an arbitrary number of subtrees of the same type (the contents of a collection). Single value tree nodes can represent a non-containment reference by holding the id of another tree node within the same tree.

This data model is partly inspired by theATermsformat presented by van den Brand et al. (2000). We therefore call the basic type of our object tree data model aterm. In its most general form, a term is a tree node or a tree leaf with meta-information attached.

As we have seen in the example above, we need different types of terms to represent

5.2. Object Tree – A Data Model for Modelware Lenses 113

OmegaTerm<Root> CompositeTerm PrimitiveTerm

IndexedTerm

HeterogeneousTerm HomogeneousTerm

ListTerm<T>

+subterms: List<T>

...

InvalidTerm

ValueTerm<V>

+value: V

RefTerm<Ctor>

+ref:CtorTerm<Ctor>

NullRefTerm<Ctor>

TupleTerm<T1...Tn>

+subterms: T1...Tn

CtorTerm<Ctor>

Term

MapTerm<V,T>

+subterms:Map<V,T>

Figure 5.6: A meta-type hierarchy for the object tree data model

a typical object-oriented data structure. The most important is the constructor term (CtorTerm) which represents reference type instances. A constructor term has a fixed number of child terms with potentially different types, and refers to its class type Ctor – its arity and the order of its subterms is determined by its class type. Next, there are two homogeneous collection terms, i.e., where all subterms have the same type: a list term (ListTerm) and a key-valuemap term (MapTerm). The size of a homogeneous collection term is not statically fixed but can change at runtime. In contrast, atuple term (TupleTerm) is heterogeneously typed term with a statically fixed number of subterms.

In contrast to a constructor term, of which it is a generalization, a tuple term does not correspond to a class type. It is used, for instance, to represent the key-value pairs which are the children of a map term. Then we have a value term (ValueTerm) to represent

114 Chapter 5. A Compositional Language for Bidirectional Model Transformation the leaves in the tree which carry the actual data. As a special kind of value term, there is a reference term (RefTerm) which contains a non-containment reference to another constructor term. Furthermore, there is a special term which represents an empty model (OmegaTerm), and therefore refers to the model’s containment hierarchy’s root type.

Fig. 5.6 presents the hierarchy of meta-types which we use to represent models with our object tree data model. Type parameter bound are omitted for brevity –T always refers to another term type. Fig. 5.7 shows a representation of the models from Fig. 5.5 using our term types – type annotations are enclosed in square brackets; the children of a term are listed in normal round parentheses, separated by commas.

Figure 5.7: The models from 5.5 represented in a type annotated term notation Comparing the object tree data model with that of edge-labeled trees, type-annotations and implicit object-ids were added, and order of subterms now matters. Edge-labels are replaced by indices, which – in the case of a constructor term – can be mapped to field names. The term type hierarchy will help us to express type constraints on the data that a lens can handle. Together, the data model and the type hierarchy allow us to implement most of the lenses ofFocalwith similar semantics, and at the same time allow us to define further lenses which are required in an object-oriented modelware setting.