Chapter 2: Types Vs Classes and Subtyping Vs Inheritance
In Scala we have predefined classes and we can create our own classes as well, which are we called user-defined classes. But sometimes, we are using Class and Type words interchangeably, is it correct? Not exactly. Types and Classes are two different things and in the layman terms, we can say that Classes can be Types but not vice versa.
Types are an abstraction which contains behavior but Classes are concrete implementation, which contains the properties and behavior.
Most of the Java/Scala backgrounds always have an illusion, about these two are the same. But while looking at other language(s) like Haskell and OCaml, the picture is clear. Now, we have some brief idea about that Types and Classes are different.
Now, do you think SubTyping and Inheritance are same? Not exactly, the implementation of subtyping and inheritance still depends on language to language and according to mathematics, these are different. In languages like OCaml, it supports structural subtyping while in Java/Scala they support nominal subtyping.
Madhavan Mukund explains SubTyping and Inheritance with a beautiful way in his lecture notes called Programming Language Concepts. He explains like this way:
Sub Typing
Subtyping concept is generally based on the principle called Liskov Substitution principle where type B is a subtype of A if every function invoked on an object type of A is also be invoked in object type of B. Languages like Java/Scala we can use inheritance as of subtype perspective. But Scala is a mixture of both OOP and FP, so we can use a bit of structural subtyping via duck typing design pattern. Madhavan Mukund explains this with the help of examples, where we are going to convert into Scala code.
In the above examples, we have a Queue
, Stack
, and Deque
. The Queue
contains two methods deleteFront
and insertRear
. The stack contains two methods insertFront
and deleteFront
. Dequeue
contains four methods, deleteFront
, insertRear
, insertFront
and deleteFront
. In the application, if we are using Queue
and Stack
, we can easily replace Queue and Stack with DeQueue
even there is no inheritance relationship between these classes but not vice versa. Like below code:
In that case, we can say that Dequeue
is a subtype of Queue
and Stack
. Because according to Liskov Substitution, if B is replaced by A then B is a SubType of A.
Inheritance
Inheritance is used in the perspective of code reusability, if class A has some properties or behaviors, with help of inheritance we can reuse those behaviors.
According to the above example, Queue, Stack and Deque have different method names, but the implementation of deque methods are same as Queue and Stack method. So, in that case, we can say that there is no subtyping between Quest and Deque or Stack and Deque, but can create the inheritance relationship between them, because of code reusability. Like in the below example:
Languages like Scala/Java, it is really difficult to separate out these concepts because via inheritance subtyping is also associated. But these concepts are actually different and used for a specific purpose.
Nominal Typing
Jamie Kyle gives a beautiful and simple example of Structural Typing vs Nominal typing within his blog. Let’s see, how can we implement Nominal and Structural subtyping in Scala.
Structural Subtyping
In Scala Structural Subtyping is also called Duck Type design pattern, where we can say, if it walks like a duck, quack like a duck so, we can say that, it is a duck. As per scala best practices, we need to avoid this structural subtyping, because of internally it uses reflection which makes our code slow.
Note: In Java or Scala for achiveing subtyping we generally using inheritence. So, in this book we will be using subclass and subtype interchangeably.
Last updated