Null and null:
- First, let’s tackle Null and null.
- Null is a trait, which (if you’re not familiar with traits) is sort of like an abstract class in Java.
- There exists exactly one instance of Null, and that is null.
- The literal null serves the same purpose as it does in Java.
- It is the value of a reference that is not referring to any object.
- So if you write a method that takes a parameter of type Null, you can only pass in two things: null itself or a reference of type Null.
def tryit(thing: Null): Unit = {
println("That worked!");
}
tryit(null); // That worked! ==> Allowed
// we try to pass in a String, and of course that doesn’t work.
tryit("hello"); // Not Allowed
/*
type mismatch;
found : String("hello")
required: Null
*/
// we try to pass in a null reference, but that doesn’t work either, because the reference is String, just the value is null. Here the reference needs to be Null.
val someRef: String = null;
tryit(someRef); // Not Allowed
/*
type mismatch;
found : String
required: Null
*/
val nullRef: Null = null;
tryit(nullRef); // That worked! ==> Allowed
Nothing:
- Nothing is another trait.
- It extends class Any.
- Any is the root type of the entire Scala type system.
- An Any can refer to object types as well as values such as plain old integers or doubles.
- trait Nothing extends Any
- There are no instances of Nothing.
Use Cases of Nothing In Scala:-
If Nothing does not have any instances, then when do we use this one in Scala Applications?
- Nil is defined using Nothing.
- None is defined using Nothing.
object Nil extends List[Nothing]
object None extends Option[Nothing]
- We can use Nothing as a return type of methods which never return.
- We can use Nothing as a return type of methods which terminates abnormally.
- Nothing is a subtype of everything. Nothing is a subtype of List, it’s a subtype of String, it’s a subtype of Int, it’s a subtype of YourOwnCustomClass.
- Since Nothing is a subtype of everything, Nil can be used as an empty List of Strings, an empty List of Ints, an empty List of Any. So Nothing is useful for defining base cases for collections or other classes.
// we assign a List[Nothing] to a reference to List[String]. A Nothing is a String, so this works.
val emptyStringList: List[String] = List[Nothing]() // Works fine.
// we assign a List[Nothing] to a reference to List[Int]. A Nothing is a Int, so this works.
val emptyIntList: List[Int] = List[Nothing]() // Works fine.
val emptyStringList: List[String] = List[Nothing]("abc") // Error
/*
type mismatch;
found : String("abc")
required: Nothing
*/
A Nothing is a subtype of everything. But both of these List[Nothing] instances contain no members. What happens when we try to create a List[Nothing] containing a String and assign that List to a List[String] reference? It fails because although Nothing is a subtype of everything, it isn’t a superclass of anything and there are no instances of Nothing. So any collection of Nothing must necessarily be empty.
Nil:
Nil is an object, which is used to represent an empty list. It is defined in “scala.collection.immutable” package as shown below:
object Nil extends List[Nothing]
Example:-
scala> Nil
res4: scala.collection.immutable.Nil.type = List()
scala> Nil.length
res5: Int = 0
scala> Nil + "ABC"
res6: List[java.lang.String] = List(ABC)
scala> Nil + Nil
res7: List[object Nil] = List(List())
None:
When you’re writing a function in Java and run into a situation where you don’t have a useful value to return, what do you do? There are a few ways to handle it. You could return null, but this causes problems. If the caller isn’t expecting to get a null, he could be faced with a NullPointerException when he tries to use it, or else the caller must check for null. Some functions will definitely never return null, but some may. As a caller, you don’t know. So, you may run into NullPointerException which you need to handle using throws keyword. But there is a cost associated with try/catch blocks, and you usually want to reserve the use of exceptions for truly exceptional situations, not just to signify an ordinary no-result situation.
Scala has a built-in solution to this problem. If you want to return a String, for example, but you know that you may not be able to return a sensible value you can return an Option[String]. Here’s a simple example.
def getAStringMaybe(num: Int): Option[String] = {
if (num >= 0) Some("A positive number!")
else None
}
val value = getAStringMaybe(10);
println(value); // Some("A positive number!")
value match {
case Some(str) => println(str)
case None => println("No string!")
} // A positive number!
val value = getAStringMaybe(0);
println(value); // None
value match {
case Some(str) => println(str)
case None => println("No string!")
} // No String
The method getAStringMaybe returns Option[String]. Option is an abstract class with exactly two subclasses, class Some and object None. Those are the only two ways to instantiate an Option. So getAStringMaybe returns either a Some[String] or None. Some and None are case classes, so you can use the handy match/case construct to handle the result. None is object that signifies no result from the method.
The purpose of an Option[T] return type is to tell callers that the method might return a T in the form of a Some[T], or it might return None to signify no result. This way, the caller supposedly knows when he does and does not need to check for a good return value.
Unit:
In Scala, Unit is used to represent “No value” or “No Useful value”. Unit is a final class defined in “scala” package that is “scala.Unit”.
- Java’s void does not any value. It is nothing.
- Scala’s Unit has one value ()
- () is the one and only value of type Unit in Scala. However, there are no values of type void in Java.
- Java’s void is a keyword. Scala’s Unit is a final class.
Both are used to represent a method or function is not returning anything.

