﻿

















          Adding expressiveness:     
            Generics in Java







Investigated in GJ








Introduced in last versions of Java






Exercise: is it precisely GJ that was implemented?








GJ adds parametric polymorphism in Java

(besides the subtyping polymorphism)










Similar to Haskell polymorphism


Example: List of T      [a]













C++ uses templates in order to have type parametricity













Poor! 





      -  type-checked at instantiation time

- instantiations compiled into disjoint code segments









        Review of Java



Remind: 
Java has invariant type system 
(no change in parameter and result types 
 in redefined methods in subclasses)








    -Recalling Interfaces-


Interfaces similar to object-types.


So, Interface extensions can be interpreted as subtyping






   - parameterized stack -









In normal Java

In order to overcome the need of parameterized classes:


          A trick : stack of Objects









public class Stack extends Vector {
   public void push(Object item){...}
   public Object pop(){...}
   public Object peek(){...}
   public boolean empty(){...}
   public int search(Object o){...}
}









In the following example it works fine



Stack myStack = new Stack();
Point aPoint = new Point(2,3);
myStack.push(aPoint);


BUT....












try to pop an element (point) and to move it


           myStack.pop().move(1,2)


   For the Type system it is an Object! 
                No move!










A cast needed


((Point)myStack.pop()).move(1,2)



Consistency checked at run-time!!













Construct 'instanceof' to avoid exception raising
















Even more complicated in case of stack of int elements.



A number needs to be made an object (by wrapping)






















pushing and popping of a number in a "simple" way


            myStack.push(new Integer(n))


         ((Integer)(myStack.pop())).intValue()







So, Drawbacks:

   - Stacks cannot be forced to hold uniform 
     elements

   - cast needed after popping


a trick is nothing more than  a trick....










GJ introduced Parameterized Types


 


public class Stack<Elt> extends Vector<Elt>{
   public void push(Elt item){...}
   public Elt pop(){...}
   public Elt peek(){...}
   public boolean empty(){...}
   public int search(Elt o){...}
}



Stack<Point> myStack = new Stack<Point>();
Point aPoint = new Point(2,3);
myStack.push(aPoint);









Point stackPoint = myStack.pop().move(1,2);


no cast needed!







          - GJ offers Bounded Polymorphism -




Orderable interface:

public interface Orderable {
   boolean equal(Orderable other);
   boolean greaterThan(Orderable other);
   boolean lessThan(Orderable other);
}



lists of orderable objects;





public class OrderedList<Elt implements Orderable>
                        extends ... {
   public void insert(Elt item){...}
   public Elt removeFirst(){...}
   public boolean empty(){...}
   public int searchFor(Elt o){...}
}
 






somewhat Similar to Haskell
              Ord a => ...  






Drawback:

It is hard to implement Orderable!














class IntOrd  (ordered integers) 



public class IntOrd implements Orderable {
   protected int value = 0;
   ...
   public boolean greaterThan(Orderable other){
      if (other != null && other instanceof IntOrd){
         return (value > ((IntOrd)other).value)
      } else { ... raise an exception??...}
   }
   ...
}




check needed in body!  
(something else than IntOrd admissible as argument)








IntOrdBC would be normally defined instead of IntOrd 
(but id does not implement Ordered...)





public class IntOrdBC {
   protected int value = 0;
   ...
   public boolean greaterThan(IntOrdBC other){
      return (value > other.value);
      }
   }
   ...
}






So: difficulties in using bounded polymorphism 
with binary methods!






A generalized form of bounded polymorphism: 

                ** F-bounded polymorphism **















 an example of use


interface OrderableF<T> {
   boolean equal(T other);
   boolean greaterThan(T other);
   boolean lessThan(T other);
}



The class IntOrdBC above can implement 

OrderableF<IntOrdBC>






Now 

 public class IntOrdBC 
        implements Orderable<IntOrdBC> 
    ...}


so IntOrdBC could be used as parameter for




public class BPOrderedList<Elt implements                                  
                            OrderableF<Elt>>
             extends ... {
   public void insert(Elt item){...}
   public Elt removeFirst(){...}
   public boolean empty(){...}
   public int search(Elt o){...}
}
   
               

Easyly checked by the type system whether

    C implements OrderableF<C>





example of use:


BPOrderedList<IntOrdBC> ordListSC

                  = new BPOrderedList<IntOrdBC>();

IntOrdBC o = new IntOrdBC();

ordListSC.insert(o);
...       











So,

Expressiveness extended!!!













Bad interaction of F-bounded polymorphism

 with 

subclass or subtype hierarchies













Expected:

If C satisfies an F-bounded constraint &  SC extends C

    then  SC satisfies the constraint as well















True for bounded, but not for F-bounded!!

Example:

   IntOrdBC  

   ExtIntOrdBC 

   <Elt implements OrderableF<Elt>>


public class ExtIntOrdBC extends IntOrdBC {
   ...

   public boolean greaterThan(IntOrdBC other){

      return (value > other.value) && ...
     }
   }
   ...
}


The problem is in the "...(IntOrdBC other)" parameter.

Java is invariant!



So, NO ordered lists of ExtIntOrdBC object possible!







In case we could have  "...(ExtIntOrdBC other)"

F-bounded constraint satisfied, BUT

ExtIntOrdBC is not a subtype of IntOrdBC!!

Cause: covariant change in type of arguments










No Sect. 4.2.












            UNDERSTANDING SUBTYPES


General definition of subtype.   <--- we already know that!


Understanding subtyping by means of 
records and record-types                
<--- We did it!! 
In particular for arrow types








Types of variables <-- we have not 
                    considered it yet




x:=x+1




variable as    l-value (location)
         and   r-value (proper value stored)






consider
          x:FoodType
          y:CheeseType

where
        CheeseType <: FoodType






so  x := stigghiola    OK!





    y:= pepato-fresco  OK!






    x:= y              OK!





    x:= maccu          OK!




can we replace now x by y in the expression "x:= maccu"?

It seems so, since   CheeseType <: FoodType

  we get   y:=maccu   WRONG!





Problem  variable as l-value have type

                Ref Type          




     Ref FoodType <: Ref CheeseType






So, x as r-value can be replaced by y
    y as l-value can be replaced by x




But in programming languages x and y denote at the same time
both the uses!!!



So, the only way out:

    Ref S' <: Ref S  iff  S' equivalent to S





The same discussion leads to the subtype rule for

UPDATABLE records and arrays


Array[IndexType']of S'<:Array[IndexType]of S

                      iff

IndexType'<:IndexType and S'equivalent to S



Remind that no such problem for records in Functional Programming
where there is NO UPDATE










Subtyping rule for arrays in Java:

  S'[] <: S[]   iff  S'<: S


NOT SOUND!!









Problems! as exemplified by following example


class BreakJava{
   C v = new C();
   void arrayProb(C[] anArray){
      if (anArray.length > 0)
          anArray[0] = v; // ( 2 )
   }

   static void main(String[] args){
      BreakJava bj = new BreakJava();
      CSub paramArray = new CSub[10];
      bj.arrayProb(paramArray); // ( 1 )
      paramArray[0].methodOfCSubOnly(); // ( 3 )
   }
}




Java allows

            bj.arrayProb(paramArray)

where paramArray is an array of CSub elements 
      and arrayProb expects array of C as argument 

OK for Java, since for Java CSub [] <: C[]

This leads, at run time, to

              paramArray[0] = v 
   
where paramArray[0] is a CSub variable, whereas v is a C element  DANGER!!

In fact  
         paramArray[0].methodOfCSubOnly()    COULD CRASH!!!




A patch: extra dynamic checks

Java compiler inserts a dynamic check before executing

            anArray[0] = v

that is, before the actual paramArray[0] = v




But we go OUTSIDE the static type system



Java’s unsafe subtyping rule for arrays allows any array
of elements that implement Comparable to be passed to sort methods,
even though they are in theory vulnerable to the same errors as 
illustrated above.

Java trades FLEXIBILITY against TYPE-SAFENESS


                        A GOOD CHOICE ???









    Object Types

Good typing rules for them like immutable records
(in fact only method types in an object type)




These rules must be considered for type-safe changes
in parameters and result types in methods of subclasses

--->> but ONLY if if we wish subclasses to generate subtypes  !!!




In case we do not?

Are there restrictions to be followed???





We skip 5.3!!




             






       






