2

Traits - The beauty of Scala - Knoldus Blogs

 2 years ago
source link: https://blog.knoldus.com/traits-the-beauty-of-scala/
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
Reading Time: 4 minutes

In this blog we will discuss about a Trait and how Traits can help you to beautify your code by Multiple Inheritance.

Traits

Traits are a fundamental unit of code reuse in Scala. Trait encapsulates method and field definitions, which can be reused by mixing into classes.

Two most important concept about Traits are :-

  • Widening from thin interface to rich interface
  • Defining stackable modifications.
trait Philosophical {
  def philosphize() {
    println("I consume memory,therefore I am !")
  }
} 

Trait can be mixed with a class using either extends or with keyword.

class Frog extends Philosophical {
  override def toString = "green"
}

As we know that Frog is a class which is a child class of AnyRef but it extends a Trait which also extends a class AnyRef so we can say that Frog will have a parent class or Trait as Philosophical which will extend the class AnyRef. Frog will not have a direct connection to AnyRef, it will first extends Philosophical which will further extends AnyRef.

Extending Traits

A trait can be extended by other traits, concrete class, abstract class and case class as well.

Traits extending a Traits

trait Animal {
  def foo() {
    println("This is a type of Animal")
  }
}

trait Dog extends Animal {
  override def toString = "Dog"
}

Abstract classes can extend a trait

abstract class Frog extends Animal {}

In this case, if we have some methods or fields declared in that trait, abstract class need to override it.

Classes extends a trait

class Frog extends Philosophical {
  override def toString = "green"
} 

Thin interface V/S Rich interface

One major use of traits is to automatically add methods to a class in terms
of methods. That is, traits can enrich a thin interface making it into a rich interface.

Rich interface

In case of rich interface we may have the implementation of methods and it depends on the need of a user whether the user wants to use the definition of the methods or user can override it according to the need.

Thin interface

In case of thin interface every class which extend that class need to override those methods, in case of thin interface we will not have the definition of those methods or fields and every time we need to override those methods to provide the definition.
Suppose more than one class extends the same trait so in case of thin interface we may need to override that same method and every time need to give the definition of that method, which can be reduced by the help of rich interface, we just need to override those methods whose definition we want to change.

Stackable modification

As we know class/trait can extend more than one trait at a time and if all of those trait have same method and we need to override that method then how we will get to know that which overridden method will be invoked. In such a situation how can we resolve that thing?

Trait plays an important role here. Stackable modifications state that “super” is accessed dynamically based on how the trait is mixed in, whereas in general super is statically determined.

import scala.collection.mutable.ArrayBuffer

trait WithLegs {
  def legs: String = "Base"
}

trait TwoLegged extends WithLegs {
  override def legs: String = "Two -> " + super.legs
}

trait FourLegged extends WithLegs {
  override def legs: String = "Four -> " + super.legs
}

trait SixLegged extends TwoLegged {
  override def legs: String = "Six -> " + super.legs
}

class ClassB extends FourLegged with TwoLegged {
  override def legs = "B -> " + super.legs
}
res1: String = B -> Two -> Four -> Base

Lineraziation

Trait linearization is a process which comes in picture when ever we mix any number of traits and classes in a single trait.

Scala linearization is a process in which all traits are present in linear hierarchy, by this we can solve the diamond problem . Remember that the syntax to mixin traits is as follows: class A extends B with C with D.

The rules for this process are as follows:

  1. Start from the very first class or trait which is extended and write the linearized hierarchy.
  2. Take the next trait and write this hierarchy down
    • now remove all those classes and traits which we have already used in our previous linearized hierarchy.
    • add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy.
  3. repeat step 2 for every trait.
  4. Place the class itself as the last type extending the linearized hierarchy.
class Beast extends TwoLegged with FourLegged {
  override def legs = super.legs
}

Without the Linearization process it would be unclear where the super.legs resolves to because of the linearization process, the compiler determines that super points to FourLegged.

Let’s write this down by applying the rules mentioned above:

  1. Start at the first Start at the first extended class or trait and write that complete hierarchy down. The first trait is TwoLegged, so this leads to:
    TwoLegged -> AnyRef -> Any
  2. Take the next trait and write this hierarchy down. The next trait is FourLegged and the hierarchy is:
    FourLegged -> AnyRef -> Any
    • now remove all classes/traits from this hierarchy which are already in the linearized hierarchy. This removes AnyRef and Any, so we are left with:
      FourLegged
    • add the remaining traits to the bottom of the linearized hierarchy to create the new linearized hierarchy
      FourLegged -> TwoLegged -> AnyRef -> Any
  3. repeat step 2 for every trait. There are no more traits, so we are done.
  4. Place the class itself as the last type extending the linearized hierarchy
    Beast -> FourLegged -> TwoLegged -> AnyRef -> Any

The graphical representation looks like the picture below:

linearized-multiple-inheritance

This hierarchy clearly shows that calling super from Beast will resolve to the FourLegged trait and thus the value of legs will be 4.

Hope this block will help you.

Happy Blogging!


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK