Traits in Scala are similar to interfaces in Java. However, they offer substantial enhancements to Java interfaces. They can also be used in Java classes under certain conditions.
Traits encapsulate methods and fields which can be reused and mixed with classes. Scala allows both abstract and concrete methods and variables, unlike Java interfaces which have only abstract methods. So in some sense traits are like similar to classes except that it has a keyword trait in front of it when it is defined.
Let’s define a trait which has two abstract variables and one abstract method. See Below
Extending Traits
Traits can be extended to create new traits. See Below
While extending traits it is not necessary to implement the abstract methods. It is also possible to create traits with a mix of abstract and concrete methods which was not possible in Java. See Below
Extending Classes with Traits
Once a trait is defined it can be used to extend a class to exhibit a certain behaviour by implementing all the abstract methods and variables defined in the trait. Let’s see the example. See Below.
val name : String
val price : Int
def getDiscount():Double
def getSellingPrice:Double
}
trait FlavoredIceCream extends IceCream{
val flavour : String
}
class chocolateIceCream(pName:String,pPrice:Int) extends FlavoredIceCream{
override val name: String = pName
override val price: Int = pPrice
override val flavour: String = "Chocolate"
override def getDiscount(): Double = {
if (price >= 10) 0.1 else 0.2
}
override def getSellingPrice(): Double = (1-getDiscount)*price
}
val belgianDark = new chocolateIceCream("belgian dark", pPrice = 10)
//Prints - beligian dark
println(belgianDark.name)
//Prints - 10
println(belgianDark.price)
//Prints - 9
println(belgianDark.getSellingPrice)
In the above example, class chocolateIceCream implements FlavoredIceCream trait. All the abstract members and variables are implemented in the trait. override keyword is used before the abstract methods before they are implemented in the class. Traits can also be used to extend abstract classes.
Extending classes with multiple traits
It is possible to implement not just single traits but multiple traits similar to Java using the with operator. The rules remain the same. Say suppose we want to add manufacturer information about the ice cream. See Below
val factoryName : String
val location : String
def getDescription: String
}
trait IceCream{
val name : String
val price : Int
def getDiscount:Double
def getSellingPrice:Double = (1 - getDiscount) * price
}
trait FlavoredIceCream extends IceCream{
val flavour : String
}
class chocolateIceCream(pName:String, pPrice:Int, pManufName:String, pLocation:String) extends FlavoredIceCream with Manufacturer{
override val name: String = pName
override val price: Int = pPrice
override val flavour: String = "Chocolate"
override val factoryName: String = pManufName
override val location: String = pLocation
override def getDiscount: Double = if (price >= 10) 0.1 else 0.2
override def getDescription: String = factoryName + ' - ' + location
}
val belgianDark = new chocolateIceCream("belgian dark",10,"Ben & Jerry","US")
//Prints - beligian dark
println(belgianDark.name)
//Prints - 10
println(belgianDark.price)
//Prints - 9
println(belgianDark.getSellingPrice)
//Prints - Ben & Jerry - US
println(belgianDark.getDescription)
Let’s make traits a bit more interesting. Scala allows for modifying the class composition without modifying the class hierarchy.
See the example below. There are two objects created – bread and vanillaIceCream. The bread object does not extend the IceCream trait however if you observe the vanillaIceCream object extends the trait IceCream and hence has additional members flavor and color available in the object.
val flavor : String
val color: String
}
class Product(pName: String, pPrice: Int, pDiscount: Double) {
val name = pName
val price = pPrice
val discount = pDiscount
def getSellingPrice:Double = (1-discount)*price
}
val bread = new Product("Seven Seeds",10,0.2)
val vanillaIceCream = new Product("IceCream Cup", 20, 0.1) with IceCream{
override val flavor: String = "Vanilla"
override val color: String = "White"
}
println(bread.name)
println(vanillaIceCream.name)
println(vanillaIceCream.flavor)
Limiting the classes which extend Traits
It is possible to limit which classes are allowed to extend a particular trait. There are a couple of ways to do that one is by using an abstract class before the trait. The other method is providing the class information in the trait itself. See Below
In the above code the only the class Product can implement the trait IceCream.
Sealed Traits
A sealed trait can be extended only in the same file in which it is declared. They are in a way used to limit the number of subtypes. Usually, they are used as an alternate to enumerations in Scala as. Sealing a trait is done by placing a modifier sealed before the trait keyword. See Below
Hope this blog entry has given you a good idea. Next we look at case objects and enumerations.
Till then!