Presentation is loading. Please wait.

Presentation is loading. Please wait.

Genericity Ranga Rodrigo Based on Mark Priestley's Lectures.

Similar presentations


Presentation on theme: "Genericity Ranga Rodrigo Based on Mark Priestley's Lectures."— Presentation transcript:

1 Genericity Ranga Rodrigo Based on Mark Priestley's Lectures

2 What is Genericity? Generic components in programming languages are a means of providing reusability of source code. The classic use of generics is to implement resuable data structures, such as lists, trees and so on.

3 What is Genericity? Such classes need to know very little about the data that is being stored in them: the source code for a list of integers will be almost identical to that for a list of strings, for example. What is required is a secure way to write, for example, a list class which can be used to store data of different types at different times, without changing the source code.

4 Genericity in Untyped Languages This happens automatically in an untyped language, such as Perl. Untyped languages place no restriction on what can be stored in a data structure. Consequences of this are: Code reuse is enabled: a single list can store data integers on one occasion and strings on another. Data structures can be heterogeneous: a single structure can store data of a mixture of types. It is the programmer's responsibility to remember what data is in the list: this is a common source of programming errors.

5 Using inheritance Inheritance is a mechanism for code reuse, so it is natural to wonder if it can be used for generic data structures. This is done by identifying a root class in the inheritance hierarchy, and storing references to this class in the data structure. By inheritance, the data structure can then hold data of any sort.

6 Using inheritance For example, some of the Java classes follow this approach, such as the java.util.Vector class. public class Vector { protected Object elementData[] ; public Object firstElement() {... } public void addElement(Object obj) {... } }

7 Using inheritance This data structure stores an array of references to Object, and the methods for inserting and accessing data items in the vector are defined in terms of Object. Because a reference to any Java class can be converted to a reference to Object, this means that any Java object can be stored in a vector, and hence that the vector class can be reused to store different data types.

8 Using inheritance Vector personVector, moduleVector ; Person p = new Person("John") ; Module m = new Module("3SFE613") ; personVector.addElement(p) ; moduleVector.addElement(m) ;

9 Insecurity Due to Using Inheritance However, in some ways this reintroduces an untyped element into an otherwise typed language. When you retrieve an object from a vector, you have to perform an (insecure) cast to get it back to its original type: Person p = (Person) personVector.firstElement();

10 Using Inheritance Also, this approach allows heterogeneous data structures: Finally, the vector class cannot be used for data of Java's basic types, as they are not class- based and so do not inherit from Object. moduleVector.addElement(p) ;

11 Parameterized Classes A better solution to this problem is to provide classes with type parameters: These are known as generic classes in Eiffel. C++ provides a similar facility with templates. class VECTOR[G] feature addElement(g : G)... firstElement : G... end

12 Generic Classes Because the type is a parameter, an actual type must be provide before the class can be used: this process is called derivation or instantiation: Note that one generic class can give rise to many types, one for each possible value of the generic parameter. people : VECTOR[PERSON] modules : VECTOR[MODULE]

13 Generic Classes: Compiler Detects The compiler can now detect attempts to store the wrong sort of data in a vector, and type errors when data is removed from the list can be detected: Also, data of any type can be stored, so `basic types' can be used in data structures as well as class types (this applies to mixed languages like C++ as well as to pure OO languages like Eiffel). people.addElement(m) -- type error m := modules.firstElement -- type error

14 Using Generic Entities Inside the definition of a generic class, you know virtually nothing about the generic parameter, so the class is limited to basic operations such as assignment, testing for equality and so on. In many data structures, the data is purely passive, so this is all that is required. We might have a requirement to add together two vectors, however, by adding their matching components. You could try to implement this as follows:

15 class VECTOR[G] inherit ARRAY[G] feature add(v : VECTOR[G]) : VECTOR[G] is do from i := lower until i > upper loop Result.put( item(i) + v.item(i), i) end

16 However, the compiler has no way of telling that the elements in the vector support the + operation, so this will not compile. What is required is a way of specifying that any class substituted for the generic parameter must have certain properties. In Eiffel, this is done by defining the required properties in a deferred class, rather like an interface definition in Java. In this case, we require the addition operator so we might define:

17 deferred class ADDABLE feature infix "+"(x : ADDABLE) : ADDABLE is deferred end Now what's required is a way of specifying, in the VECTOR class that only classes which are descendants of ADDABLE are acceptable instantiations of the generic parameter. This is done by using constrained genericity, as follows:

18 class VECTOR[G -> ADDABLE] inherit ARRAY[G] etc

19 Genericity and Inheritance As the examples above have illustrated, genericity and inheritance are orthogonal mechanisms in Eiffel, meaning that the use of one does not affect the possible uses of the other. In particular, a generic class is a perfectly normal class, and can be specified as a parent of another class. Finally, polymorphic data structures can be achieved in Eiffel by providing a generic parameter of a suitable parent class:

20 bank : VECTOR[ACCOUNT] The bank object will be able to store accounts of any class derived from ACCOUNT. Extracting items from such a list runs into the same issue as with Java data structures, namely that you don't know what class an extracted object belongs to. Eiffel doesn't permit casting: instead you can use a reverse assignment attempt: If the first item in the bank vector is not a savings account, s will be Void after this attempt. s : SAVING_ACCOUNT s ?= bank.item(1)

21 If the first item in the bank vector is not a savings account, s will be Void after this attempt.


Download ppt "Genericity Ranga Rodrigo Based on Mark Priestley's Lectures."

Similar presentations


Ads by Google