In Scala, typing systems are used to define and enforce the rules for how different types interact with each other. There are two main approaches to typing systems: structural typing and nominal typing.
1. Structural typing:
Structural typing is a type system where compatibility and equivalence between different types are determined by their structure. In other words, two types are considered compatible or equivalent if they have the same members (methods, fields, or properties) with the same signatures.
Scala supports structural typing with the help of ‘AnyRef‘ and the ‘type‘ keyword. Here’s an example:
type Closeable = { def close(): Unit }
def closeResource(closeable: Closeable): Unit = {
closeable.close()
}
class File {
def close(): Unit = println("File closed.")
}
val file = new File()
closeResource(file) // The method works, as File has a close() method that matches the structure.
In this example, there is no need to explicitly declare that the ‘File‘ class implements some interface or extends some base class with the ‘close()‘ method. The ‘closeResource‘ method takes a parameter of type ‘Closeable‘ and the ‘File‘ class has the same structure (a ‘close()‘ method) that the ‘Closeable‘ type expects, so it’s possible to call ‘closeResource‘ with a ‘File‘ instance.
2. Nominal typing:
Nominal typing is a type system where types are compatible or equivalent based on their names. In nominal typing, two types with the same structure are still considered different unless they have the same name or one type explicitly extends or implements the other one.
Scala uses nominal typing as its primary typing system. Here’s an example of nominal typing using traits:
trait Closeable {
def close(): Unit
}
class File extends Closeable {
def close(): Unit = println("File closed.")
}
def closeResource(closeable: Closeable): Unit = {
closeable.close()
}
val file = new File()
closeResource(file) // The method works, as File extends Closeable.
In this example, we define a trait ‘Closeable‘ with a ‘close()‘ method, and a ‘File‘ class extending it. The ‘File‘ class is thus considered to be of the type ‘Closeable‘, and it’s possible to call the ‘closeResource‘ method with a ‘File‘ instance.
To sum up, the main difference between structural and nominal typing in Scala is:
- Structural typing: types compatibility is based on their structure (members and signatures).
- Nominal typing: types compatibility is based on their names and inheritance relationship.
Scala primarily uses nominal typing, but it also supports some level of structural typing through the ‘type‘ keyword and ‘AnyRef‘.