1. Introduction To understand the difference between an abstract class and a trait, we must first define each term. Traits are similar to Java interfaces, but they allow for the implementation of their members. Abstract classes, on the other hand, are created using the `abstract` keyword and can include both abstract and concrete methods.
2. Commonalities Identifying the similarities helps clarify the differences. Let’s examine these features. A trait that has a declared and implemented method along with a variable: scala trait mytrait { def myMethod(): Unit val aVal: Int val myVal = 10 def myImpMethod = { println("I am from trait") } }
An abstract class that contains both an abstract and a concrete method along with a variable: scala abstract class abstClass { def myMethod(): Unit val aVal: Int val myVal = 10 def myImpMethod: Unit = { println("I am from abstClass") } }
In the main method, neither a trait nor an abstract class can be instantiated: scala val myTObj = new mytrait // compilation error val myAObj = new abstClass() // compilation error
Classes that extend a trait or an abstract class must implement the declared methods: scala class myTClass extends mytrait { val aVal = 10 def myMethod = { println("I am from myTclass") } } class myAClass extends abstClass { val aVal = 10 def myMethod = { println("I am from myAclass") } }
The `name` serves as a constructor parameter; using a constructor parameter in a trait leads to a compilation error, while it works correctly in an abstract class.
3.2 Modifying Object Instances scala trait objectInstanceTrait { def myObjectMethod = { println("I originate from the object instance trait") } } class myTClass {} def main(args: Array[String]): Unit = { val classObjWithTrait = new myTClass with objectInstanceTrait classObjWithTrait.myObjectMethod }
Output: "I originate from the object instance trait" The method `myObjectMethod` from the trait can be accessed through a class instance. An abstract class cannot be mixed into an object instance, resulting in a compilation error.
3.3 Multiple Inheritances In multiple inheritance, a single class can inherit from more than one superclass, gaining features from all parent classes. While Scala does not allow multiple inheritance with classes, it can be achieved using traits: scala class myClass extends trait1 with trait2{} class myNewClass extends abstClass1 with abstClass2{}
Using an abstract class for multiple inheritances results in a compilation error. Scala resolves the diamond problem in multiple inheritance through trait linearization, where the rightmost trait takes precedence: scala trait Printer { def print(msg: String) = println(msg) } trait DelimitWithHyphen extends Printer { override def print(msg: String) = { println("-------------") } } trait DelimitWithStar extends Printer { override def print(msg: String) = { println("*") } }
class CustomPrinter extends Printer with DelimitWithHyphen with DelimitWithStar
new CustomPrinter().print("Hello World!")
Output: "*"
3.4 Stackability Stackable traits in Scala allow for the combination of multiple traits that collaboratively modify a method. This involves calling `super.theMethod`: scala trait base { def baseMethod(s: String): Unit = println(s) }
trait stack1 extends base { override def baseMethod(s: String): Unit = println("from stack1") }
trait replace1 extends base { abstract override def baseMethod(s: String): Unit = { super.baseMethod(s); println("from replace1") } }
class Stackable { this: base => def apply() { println(baseMethod("bottom")) } }
(new Stackable with stack1 with replace1)()
Output: from stack1 from replace1 The invocation starts with `replace1`, which then calls `stack1` via `super.baseMethod(s)`.
3.5 Interoperability with Java Traits can seamlessly integrate with Java as long as they lack any implementation; abstract classes can be used directly.
تعليقات