The with Keyword in Scala
This article will demonstrate how to use the with
keyword in Scala.
Use the with
Keyword in Scala
This keyword is usually used when dealing with class compositions with mixins. Mixins are traits that are used to compose a class.
This is somewhat similar to a Java class that can implement an interface.
Let’s see an example to understand the with
keyword better:
abstract class vehicle {
val message: String
}
class Car extends vehicle {
val message = "I'm an instance of class vehicle"
}
trait sportsCar extends vehicle {
def ourMessage = message.toUpperCase()
}
class temp extends Car with sportsCar
val obj = new temp
println(obj.message) // I'm an instance of class vehicle
println(obj.ourMessage) // I'M AN INSTANCE OF CLASS VEHICLE
In the above code, the class temp
has superclass Car
and mixin sportsCar
. A class can extend only one superclass but many mixins using the with
keyword; a superclass and mixins can have the same supertype
.
Let’s look at another example. First, let us create an abstract class with a type T
and some standard iterator methods.
abstract class ourIterator {
type T
def hasNext: Boolean
def next(): T
}
Now, let’s create a concrete class where all the abstract members’ implementations of T
, which are hasNext
and next
, are present.
class StringIterator(str: String) extends ourIterator {
type T = Char
private var i = 0
def hasNext = i < str.length
def next() =
{
val ch = str.charAt(i)
i += 1
ch
}
}
Let’s create a trait that also extends the class ourIterator
.
trait anotherIterator extends ourIterator {
def foreach(X: T => Unit): Unit = while (hasNext) X(next())
}
The trait anotherIterator
implements the foreach()
method calling the function X: T => Unit
continuously on the next element next()
as long as there are more elements while(hasNext)
.
Since anotherIterator
is a trait, it does not need to implement any abstract members of the ourIterator
class. Now we can combine the functionalities of anotherIterator
and StringIterator
into a single class, as shown below:
class temp extends StringIterator("Tony") with anotherIterator
val obj = new temp
obj.foreach(println)
Full working code:
abstract class ourIterator {
type T
def hasNext: Boolean
def next(): T
}
class StringIterator(str: String) extends ourIterator {
type T = Char
private var i = 0
def hasNext = i < str.length
def next() =
{
val ch = str.charAt(i)
i += 1
ch
}
}
trait anotherIterator extends ourIterator {
def foreach(X: T => Unit): Unit = while (hasNext) X(next())
}
class temp extends StringIterator("Tony") with anotherIterator
val obj = new temp
obj.foreach(println)
Output:
T
o
n
y
In the above code, the new class temp
has StringIterator
as a superclass
and anotherIterator
as a mixin. Just with single inheritance, achieving this level of flexibility will not be possible.