• Ingen resultater fundet

The Library Classes

In document Translation of a Subset of RSL into Java (Sider 131-135)

Implementation of the Translator

This chapter describes some of the details of the implementation of the trans-lator. It starts, in Section 4.1, with an introduction to the library classes developed for representations of lists, sets and maps. Afterwards, in Sec-tion 4.2 and 4.3, there is a presentaSec-tion of the two versions of the translator implemented in this project.

Each of the three interfaces contains methods corresponding to the opera-tors of the complex type it represents. The three classes are implementations of these interfaces.

The interfaces and classes relies on the generic feature introduced in Java 1.5, which makes it possible to define which type of objects that may be stored in a collection. This feature removes the need for type casting when retrieving an object from a collection. Another feature, which was added in Java 1.5 is boxing and unboxing of primitive types, which removes the need for wrapping a primitive type in a wrapper class, when an object is needed and unwrap a primitive type from a wrapper class, when a primitive type is needed.

Two listings of code are shown in Example 4.1. The two examples show an ArrayList of Integer’s. The first listing is written in code complying to Java 1.4, whereas the second listing is written in code complying to Java 1.5.

Example 4.1 Generic types, boxing and unboxing in Java 1.5.

Java 1.4

A r r a y L i s t a l = new A r r a y L i s t ( ) ; a l . add (new I n t e g e r ( 5 ) ) ;

a l . add (new I n t e g e r ( 6 ) ) ;

System . out . p r i n t l n ( ” a l ( 0 ) + a l ( 1 ) : ” + ( ( ( I n t e g e r ) a l . g e t ( 0 ) ) . i n t V a l u e ( ) + ( ( I n t e g e r ) a l . g e t ( 1 ) ) . i n t V a l u e ( ) ) ) ;

Java 1.5

A r r a y L i s t<I n t e g e r> a l = new A r r a y L i s t<I n t e g e r>() ; a l . add ( 5 ) ;

a l . add ( 6 ) ;

System . out . p r i n t l n ( ” a l ( 0 ) + a l ( 1 ) : ” + ( a l . g e t ( 0 ) + a l . g e t ( 1 ) ) ) ;

The three default classes are implemented using a different kind of col-lection in the java.util package for each of them. RSLListDefault is based on anArrayList, RSLSetDefault is based on aHashSet andRSLMapDefault is based on a HashMap. All the classes are implemented so that a method returning a new complex type returns a modified shallow copy of the old one.

A shallow copy in this context is a new instance of a class in Java containing references to the same objects.

The use of ArrayList as base for RSLListDefault is not an optimal solu-tion, because the values in a list are not changed in RSL, therefore it is not necessary to create copies of a list – not even shallows copies to create the tail of a list. A linked list would be a more efficient choice. However, the

linked list must be implemented from scratch because the LinkedList class in the java.util package does not provide options for taking subsequences or the tail of a list. The LinkedList class in Java does implement a removeFirst

method, but the method is destructive and cannot be used for implementing the tl operator on lists. A better solution would be an implementation of a linked list, in which it is possible to create a subsequence just by returning a reference to an object somewhere in the list. In Java, exists a class, Vector, which contains a method for creating a sublist, but the Vector class is based on an array, therefore, this not an effective solution either, for the problem described.

The implementation of the methods in the interfaces are straightforward and uses the methods defined in the underlying collections for most of the work. An example of the way of implementing the methods of the RSLList-Default class using the methods in the underlying collection is the implemen-tation of the hd. hd uses the get method of ArrayList for returning the first element of the list. This method is listed in Example 4.2.

An example of the use of shallow copying is the tl method in the RSLList-Default class which creates a newArrayList (list2) of the elements i.e. a new list of references to the elements in the old list. Then tl creates a new in-stance of RSLListDefault (result) and set the internal list of result to list2

and removes the first item of the list2. The method is listed in Example 4.2.

Example 4.2 hd and tl methods in class: RSLListDefault

private A r r a y L i s t<E> l i s t ; public E hd ( ) {

return l i s t . g e t ( 0 ) ; }

public RSLListDefault<E> t l ( ) {

A r r a y L i s t<E> l i s t 2 = new A r r a y L i s t<E>( l i s t ) ;

RSLListDefault<E> r e s u l t = new RSLListDefault<E>() ; r e s u l t . l i s t = l i s t 2 ;

r e s u l t . l i s t . remove ( 0 ) ; return r e s u l t ;

}

One of the more complex methods in the library classes is the method

compose in the RSLMapDefault class, which corresponds to the map compo-sition operator in RSL. This method is listed in Example 4.3. The method does not use the generic feature of Java 1.5.0. The reason for this is that three types are involved in compose, namely:

1. The type of the domain of the inner map.

2. The type of the range of the inner map, which is equal to the type of the domain of the outer map.

3. The type of the range of the outer map.

This cannot be done using the generic feature in Java, which only allows use of the types specified in the signature of the class. Only two types are specified for RSLMap, namely the type of the domain and the type of the range of the map. The idea of the compose operator in RSL is to create a new map from the domain of the first map to the range of the second map. An entry in the new map is created if a value in the range of the first map can be found in the domain of the second map. In Java, this is done by creating a new instance of RSLMapDefault, which is returned as result.

Before returning the RSLMapDefault instance there is an iteration over the entry set of the inner map. For each entry in the inner map, it is checked, whether the value of the entry is a key in the outer map (the instance on which the method is applied). If the value of the entry is a key in the outer map, then an entry is added to the result with the key of the entry as key, and the value of applying the value of the entry to the outer map as value.

Example 4.3 compose method in class: RSLMapDefault

private HashMap<K, V> map ;

public RSLMap compose (RSLMap innerMap ) { RSLMap r e s u l t = new RSLMapDefault ( ) ;

I t e r a t o r i t e r a t o r =

innerMap . getMap ( ) . e n t r y S e t ( ) . i t e r a t o r ( ) ; while( i t e r a t o r . hasNext ( ) ) {

Map . Entry elem = (Map . Entry ) i t e r a t o r . next ( ) ; i f(t h i s. map . c o n t a i n s K e y ( (K) elem . g e t V a l u e ( ) ) ) {

r e s u l t . getMap ( ) . put ( elem . getKey ( ) ,

(V)t h i s. map . g e t ( innerMap . g e t ( elem . getKey ( ) ) ) ) ;

} }

return r e s u l t ; }

In document Translation of a Subset of RSL into Java (Sider 131-135)