Generics

Invariance In Java

FILE : JavaInvariance.java

First let's look at one example written in java to have a base for further experiments. In Java collections are invariant what means that List is not a supertype of List

   List<String> strings= new LinkedList<>();
   strings.add("aaa");
   strings.add("bbb");

   List<Object> object=new LinkedList<>();
   object.add("aaa");
   object.add(2);

// ILLEGAL IN JAVA
// object=strings;

However Java has a mechanism called use site variance which allows programmer to use wildcards in assignment and declare different relation between types.

List<? extends Object> parent=strings;

This mechanism however moves responsibility for defining correct relationship to developer in each assignment thus gives more chances to introduce a bug. Scala uses declaration site variance which solves this problem.

Arrays - bug by design

In Java you can actually assign String[] to Object[] which allow you to store integer in an array of strings. This is by design and results in ArrayStroeException in runtime. (Why this is by design -> search on the internet)

        String[] stringsArray={"aaa","bbb"};
        Object[] objectsArray=stringsArray;
        objectsArray[1]=55;

Generics In Scala

FILE : GenericsDemo.scala

First difference form Java - generics in scala are declared in square brackets.

var map:Map[String,Int]=Map()
def genericToString[T](arg : T) : String = arg.toString

You can add generic directly to a class definition and also another one to method definition so it will be resolved each time a method is called

class Wrapper[A](element:A){
      def modify[B](f:A=>B):Wrapper[B] = new Wrapper[B](f(element))
}

Invariance and covariance

Scala has two sets of collections : scala.collections.mutable and scala.collections.immutable. By default you are using immutable collections which are covariant - this means that List[Any] is a supertype of List[String]

val s:List[String] = List("aaa","bbb")
val i:List[Int]=List(1,2)

val o1:List[AnyRef] = s
val o2:List[Any] = i

This is legal because it is impossible to add an element to immutable list so you can not add integer to a collection of strings.

If you want to declare covariant structure you need to add + before generic declaration

class CovariantWrapper[+A](element:A){
      def modify[B](f:A=>B):Wrapper[B] = new Wrapper[B](f(element))
}

Nothing

Nothing type becomes really useful when working with covariant types. Becuase Nothing is a subtype of every other type then we can always do a substitution

val v:Type[Whatever] = Type[Nothing]()

so for example when working with either and defining one side we can easily set other side as Nothing

def createRight:Either[Nothing,Int]=Right(500)

Arrays

Arrays are invariant so no "java bugs by design".

 val arrayString=Array("aaa","bbb")
//    val arrayAny:Array[Any]=arrayString //error

Exercises

FILE TEST : jug.lodz.workshops.starter.generics.exercises. GenericsExercisesSpec

  1. Create typed Pair[A,B]
  2. Method which displays patch of any class
  3. Create Invariant option with proper implementation of getOrElse in None and Some
  4. Implement Covariant Option - in this exercise uncomment only part of code. Leave getOrElse for exercise 5.

results matching ""

    No results matching ""