1. Overview
When we learn any programing language, it’s always good to start with a basic type system of that language. In this article, we’ll explore the type hierarchy in Scala. We’ll cover the fundamentals of Any, AnyVal, AnyRef, Null, and Nothing.
2. Scala’s Class Hierarchy
Scala is a statically typed language and provides an option for writing better and high-performance code. The JVM checks the type at compile-time and optimizes the code for better run-time performance. Scala doesn’t support primitive types like Java, and it has a very vast and diverse type-system. We’ll cover a few important high-level type classes in Scala, as shown in the diagram below:
2.1. Any
Scala has a class Any, which is at the top position in the type hierarchy. It is the root class in the type system. In other words, all other classes in Scala are explicitly or implicitly a child of the Any class.
There are some standard methods defined in Any class, such as equals, hashCode, and toString are by default accessible to all the objects in Scala. Any class has two subclasses AnyVal(value classes) and AnyRef(reference classes). For example, let’s define a function any which takes an argument of Any type:
def any(value: Any): String = ""
Now let’s pass Any type arguments to the function any:
assert(any(1) == "")
assert(any(true) == "")
assert(any(()) == "")
assert(any("S") == "")
assert(any(null) == "")
assert(any(List()) == "")
We’ve passed various types of arguments to the function any, and it’s compatible with the Any type argument.
2.2. AnyVal
AnyVal class is the root class of all value types in Scala and child of Any class. There are nine value classes in Scala: Byte, Short, Char, Int, Long, Float, Double, Boolean, and Unit. Most importantly, all value classes are an abstract final type.
Furthermore, Scala value types are similar to Java’s primitive types except for Unit class. The Unit class is similar to Java’s Void type. In the case of the Unit class we can have only one instance value (). Therefore, we can’t instantiate the Unit class with a new keyword. In short, we can assign only literal values to value types in Scala. For example, let’s define a function anyVal below which takes a parameter of AnyVal type:
def anyVal(value: AnyVal): String = ""
Now let’s pass AnyVal type of arguments to the function anyVal:
val unit: Unit = ()
assert(anyVal(unit) == "")
val int: Int = 12
assert(anyVal(int) == "")
val bool: Boolean = false
assert(anyVal(bool) == "")
Notably, we can see the function anyVal is compatible with AnyVal type literal arguments. If we pass an argument other than AnyVal type, the compiler will complain and produce a message error: type mismatch required: AnyVal.
2.3. AnyRef
AnyRef is the root class of all reference types in Scala and child of Any class in the Scala type system. It is similar to Java’s Object class, and we can instantiate reference classes with a new keyword. Finally, Scala is adaptable with any reference classes including Java classes. For example, let’s define a function anyRef which takes an argument of AnyRef type:
def anyRef(value: AnyRef): String = ""
Now let’s define a class Person below:
case class Person(name: String)
Let’s pass a reference type arguments to the function anyRef:
assert(anyRef(new Person("Same")) == "")
In conclusion, the function anyRef is suitable for any reference type and non-suitable for non-reference type. If we pass a non–reference type to the anyRef function, the compiler will raise an error message error: type mismatch required: AnyRef.
2.4. Null
In the hierarchy, the Null class is at the bottom of all the reference types. Generally, a Null reference could be assigned to AnyRef type in the type system, but it’s not suitable for AnyVal types. The Null class is a child of all reference classes. To illustrate, let’s look at the same function anyRef below:
assert(anyRef(null) == "")
In conclusion, we can assign null literal to any reference class in Scala.
2.5. Nothing
Nothing is the child of all types including Null in the Scala type hierarchy. Generally, it has no value, we can’t assign it to any variable, and it’s not similar to Null. In short, as the name suggests, Nothing means nothing. Let’s take an example below:
val list: List[Nothing] = List()
assert(list == List())
In the above example, we defined a list which takes no values.
3. Conclusion
In this article, we covered the basics of the Scala type system and the relationship between the Scala type classes. In the end, the full source code can be found over on GitHub.