Between Option, Some and None

Some and None are sub-classes of Option where Some holds a value and None holds, well, nothing. They are used in place of if statements which are typically found in Java code e.g.

// Java code snippet
if (person != null) {
    return person.name;
} else {
    return "He shall not be named.";
}

With Option, the code is made simpler,

val personOpt : Option[Person] = ...
println("His name is " + personOpt.map(person => person.name).getOrElse("anonymous")

When Option is used in a collection,

scala> List(Some(1), Some(2), None).flatMap(_.map(_ + 1))
res0: List[Int] = List(2, 3)

None is removed during flatten which is part of flatMap process, while those with values are increased by 1.

More examples,

scala> List(Some(1), Some(2), None).map(_.map(_ + 1))
res1: List[Option[Int]] = List(Some(2), Some(3), None)

scala> List(Some("1"),Some("2"), None).map(_.map(_ + 1))
res2: List[Option[String]] = List(Some(11), Some(21), None)

scala> List(Some("1"),Some("2"), Option(null)).map(_.map(_ + 1))
res3: List[Option[String]] = List(Some(11), Some(21), None)

// flatten after the list is mapped using flatMap    
scala> List(Some("1"),Some("2"), Option(null)).flatMap(_.map(_ + 1))
res4: List[String] = List(11, 21)

and if you are not careful,

scala> List(Some(2),Some(3), Option(null)).flatMap(_.map(_ + 1))
<console>:8: error: type mismatch;
found   : Int(1)
required: String
             List(Some(2),Some(3), Option(null)).flatMap(_.map(_ + 1))
                                                                   ^

The previous statement fails because the _ in flatMap is an instance of type Any. But, where does the type Any come from? The last element null is coerced into String null i.e. “null” and together with Int 1 and 2, the final List become List[Any] because Any is the parent of both String and Int. Therefore, _ is a type of Any and the method + of Any accepts instance of type String .

A simple proof,

scala> val a: Any  = "A"
a: Any = A

scala> a + 1
<console>:9: error: type mismatch;
found   : Int(1)
required: String
             a + 1
                 ^

scala> a + "1"
res27: String = A1

By the way, null is an instance of Null class. Null is the sub-class of all AnyRef sub-classes, like Nothing is the sub-class of all sub-class of Any.

What Scala code should look after the transformation from Java

We have a Java 1.7 application where it takes a string from the argument and enumerate each letter and count the frequency of each letter,

import java.util.*;

class RunMe {
    public static void main(String[] args) {
        char[] chars = args[0].toCharArray();
        HashMap<Character, Integer> counters = new HashMap();
        for (int i = 0; i < chars.length; i++) {
            Integer count = counters.get(chars[i]);
            if (count == null) {
                counters.put(chars[i], 1);
            } else {
                counters.put(chars[i], count + 1);
            }
        }

        printMap(counters);
    }

    private static void printMap(Map<Character, Integer> m) {
        for (Iterator<Character> keyIter = m.keySet().iterator(); keyIter.hasNext();) {
            Character c = keyIter.next();
            System.out.println(c + " => " + m.get(c));          
        }
    }
}

Next, this application is transformed into a Scala application literally,

import collection.mutable._

object ScalaMe {
    def main(args : Array[String]) {
        val chars = args(0).toCharArray()
        val counters = new HashMap[Character, Int]()
        for (i <- 0 until chars.length) {
            val count = counters.get(chars(i))
            if (count == None) {
                counters.put(chars(i), 1)
            } else {
                counters.put(chars(i), count.get + 1)
            }
        }       
        println(counters)
    }
}

Yes, it seems a lot shorter but that is not the reason for Scala. That code is imperatively crafted where each step is explicit i.e. assigning values to their locations.

Yes, we can definitely do better,

object BetterMe {
    def main(args : Array[String]) {
       val counters = args(0).toCharArray.foldLeft(Map[Char, Int]())(
           (m, k) => m + (k -> (m.getOrElse(k, 0) + 1)))
       println(counters)
    }
}

And this is the way it should be done with Scala and other Functional Programming (FP) languages.

Java Generics Wildcards The Way I Understood It

Java Generics wildcards has been bothering me for some time, a long time in fact. It is not something that I could not understand or use it to my advantage in my daily work. I just could not explain why some of the Generics errors I encountered. But not this time, I must get to bottom of it, at least, the easy part of it.

Class Diagram

Apple and Orange inherit from Fruit. Further on, Fruit inherits from Plant i.e. Apple and Orange is-a Fruit is-a Plant

Apple/Orange is-a Fruit is-a Plant

Getting It Out of The Way

Let it be clear that List<Apple> and List<Orange> are not the children of List<Fruit>. For example, you simply cannot do this,

List<Apple> applesBasket = new ArrayList<>(); 
fill(applesBasket); // compilation error 
...

List<Orange> orangesBasket = new ArrayList<>(); 
fill(orangesBasket); // compilation error 
...

// add more fruits to the basket
public void fill(List<Fruit> basket) { // add fruits to basket }

but it is alright to do this,

List<Fruit> fruitsBasket = new ArrayList<>();
fruitsBasket.add(new Apple());  // compiles ok
fruitsBasket.add(new Orange()); // compiles ok

So, we must change fill(...) method signature to

public void fill(List<? super Fruit> basket) { // add fruits to basket }

to accept both List<Apple> and List<Orange>.

Why does the parameter basket is not a Covariance type parameter List<? extends Fruit>?. After all, Apple and Orange are extended from Fruit. By the way, List<? super Fruit> is a Contravariance type parameter.

PECS Rule And Generics Wildcards

The mistake was trying to add instances of supertype of Fruit to the List<? super Fruit> container e.g. add Plant instances to List<? super Fruit> in the fill(...) method. It was wrong to think that super was referring to the class parent-child relationship. super refers to the container behaviour. The basket in the method fill(List<? super Fruit> basket) consumes instances of type Fruit or subtypes of Fruit. So, according to PECS (Producer extends and Consumer super) rule, if the container is a consumer, use ? super T otherwise use ? extends T, the type parameter is ? super Fruit for this case.

If those methods used in the container are limited to those which take parameters of that type parameter, the container is a consumer. On the contrary, if the methods used by the container return instances of that type parameter, the container is a producer. Lastly, if both type of methods are used, the container is both producer and consumer. In this case, the wildcard (?) cannot be used. Examples of consumer methods are,

void public add(T o, int i);
void public remove(T o);
void public invoke(T o, int i);

and examples of producer methods are,

void T get();
void T removeAt(int i);

It is all make sense now once we have determined the super and extends type parameters and view from the caller angle. The method requires the caller to provide the right type of value to invoke the method as shown in this example,

List<Plant> plantsBasket = new ArrayList<>();
List<Fruit> fruitsBasket = new ArrayList<>();
List<Apple> applesBasket = new ArrayList<>();
...
fill(plantsBasket); // compiles ok
fill(fruitsBasket); // compiles ok
fill(applesBasket); // compilation error

It requires thinking from inside out.

Source code illustrating this article is available here

Please refer to Effective Java by Joshua Bloch for more details on PECS and Generics.

Finally, List<Object> and List<?> are not the same.

Update #1 (Sep 8 2016)

I want to illustrate the difference between List<Object> and List<?> and why raw type is a bad idea. Let us consider the following code,


public class RawListMustDie {

    public static void add10ToRaw(final List strings) {
        strings.add(10);
    }

/*  typed "strings" does the right thing and throws "no suitable method found for add(int)"
    
    public static void add(List<?> strings) {
        strings.add(10);                                    // (6)
    }
*/
    public static Object headRaw(List raw) {
        return raw.get(0); 
    } 

    public static Object headObject(List<Object> objects) { 
        return objects.get(0); 
    } 

    public static <T> T head(List<T> generics) {
        return generics.get(0);
    }

    public static void main(String[] args) {
        List<String> strings = new ArrayList<>();
        add10ToRaw(strings);                                 // (1)

        String r = (String) headRaw(strings);                // (2)
        String s = (String) headObject((List) strings);      // (3)
        String t = head(strings);                            // (4)

        // throws exception during runtime; bad
        System.out.println(strings.get(strings.size() - 1)); // (5)
    }
}

There are 3 methods to handle raw type List, List<Object> and generic List respectively. A raw type List is a List without generic. The method to handle a generic List is the best solutions. Its intention is clear and there is no type casting that might cause a runtime exception, as seen in (2) and (3).

Raw parameter method add10ToRaw(...) in (1) adds an Integer to a supposedly a list of String will throw a ClassCastException in (5). This is because in (5), the instance retrieved from the list is casted to String and this is why it crashed and burned.

(6) is commented, otherwise the source will not compile. It is a good thing that the compiler forces the developers to rectify the error early. List hints the compiler to stop developers from adding instances to a wildcard list.

A wildcard list is useful when the developer wants to access the instances in the list but the type is not required. For example, head() retrieves the first element from the list regardless of its type. It is the caller’s responsibility to manage the instant type returns from head(). However, the developer cannot declare the method parameter type List<Object> to accept List<String> because List<String> is not the subclass of List<Object> even though String inherits from Object.