Saturday, 18 May 2019

Traits


Traits
Traits are like interfaces in Java. But they are more powerful than the interface in Java because in the traits you are allowed to implement the members. Traits can have methods(both abstract and non-abstract), and fields as its members.
Some important points about Scala Traits.
Traits are created using trait keywords.
Syntax:
trait Trait_Name{
// Fields..
// Methods..
}
Example:
// create traits
// Trait 
trait MyTrait
{
    def pet 
    def pet_color
}
//MyClass inherits trait
class MyClass extends MyTrait
{
    // Implementation of methods of MyTrait
    def pet()
    {
        println("Pet: Dog")
    }    
    def pet_color()
    {
        println("Pet_color: White")
    }
    // Class method
    def pet_name()
    {
        println("Pet_name: Dollar")
    }
} 
object Main 
{
    // Main method
    def main(args: Array[String]) 
    {
        val obj = new MyClass();
        obj.pet();
        obj.pet_color();
        obj.pet_name();
    }
}
Output:
Pet: Dog
Pet_color: White
Pet_name: Dollar

In Scala, we are allowed to implement the method(only abstract methods) in traits. If a trait contains method implementation, then the class which extends this trait need not implement the method which already implemented in a trait. As shown in the below example.
Example:
// Scala program to illustrate the concept of abstract and non-abstract method in Traits
// Trait with abstract and non-abstract methods
trait MyTrait
{
    // Abstract method 
    def greeting  
    // Non-abstract method
    def tutorial
    {
        println("Umesh's blog" +  "of Traits in Scala")
    }
}  
// MyClass inherits trait
class MyClass extends MyTrait
{
    // Implementation of abstract method no need to implement a non-abstract 
    // method because it already implemented
    def greeting()
    {
        println("Welcome to Umesh's blog")
    }
} 
object Main
{
    // Main method
    def main(args: Array[String]) 
    {
        val obj = new MyClass();
        obj.greeting
        obj.tutorial
    }
}
Output:
Welcome to Umesh's blog
Umesh's blog of Traits in Scala

Traits does not contain constructor parameters. When a class inherits one trait, then use extends keyword.
Syntax:
class Class_Name extends Trait_Name{
// Code..
}
When a class inherits multiple traits then use extends keyword before the first trait and after that use with keyword before other traits. As shown in the below example.
Syntax:
class Class_Name extends Trait_Name1 with Trait_Name2 with Trait_Name3{
// Code..
}
Example:
// Scala program to illustrate how a class inherits multiple traits  
// Trait 1
trait MyTrait1
{
    // Abstract method 
    def greeting
}
//Trait 2
trait MyTrait2
{      
    // Non-abstract method
    def tutorial
    {
        println("Umesh's blog" + "of Traits in Scala")
    }
}
// MyClass inherits multiple traits
class MyClass extends MyTrait1 with MyTrait2
{
    // Implementation of abstract method
    def greeting()
    {
        println("Welcome to Umesh's blog")
    }
}   
object Main 
{    
    // Main method
    def main(args: Array[String]) 
    {
        val obj = new MyClass();
        obj.greeting
        obj.tutorial
    }
}
Output:
Welcome to Umesh's blog
Umesh's blog of Traits in Scala

An abstract class can also inherit traits by using extends keyword.
Syntax:
abstract class Class_name extends Trait_Name{
// code..
}
In Scala, one trait can inherit another trait by using a extends keyword.
Syntax:
trait Trait_Name1 extends Trait_Name2{
// Code..
}
Traits support multiple inheritance.
In Scala, a class can inherit both normal classes or abstract class and traits by using extends keyword before the class name and with keyword before the trait’s name.
Syntax:
class Class_Name1 extends Class_Name2 with Trait_Name{
// Code..
}
In Traits, abstract fields are those fields with containing initial value and concrete fields are those fields which contain the initial value. we are allowed to override them in the class which extends trait. If a field is declared using the var keyword, then there is no need to write override keyword when we override them. And if a field is declared using the val keyword, then you must write override keyword when we override them.
Example:
// Scala program to illustrate concrete and abstract fields in traits
trait MyTrait
{
    // Abstract field
    var value: Int 
    // Concrete field
    var Height = 10
    val Width = 30
}
class MyClass extends MyTrait
{
    // Overriding MyTrait's fields
    var value = 12
    Height = 40
    override val Width = 10
    // Method to display the fields
    def Display()
    {
        println("Value:%d", value);
        println("\nHeight:%d" ,Height);
        println("\nWidth:%d", Width);
    }
}
object Main
{
    // Main method
    def main(args: Array[String])
    {
        val obj = new MyClass();
        obj.Display();
    }
}
Output:
Value:12
Height:40
Width:10
We can also add traits to an object instance. Or in other words, We can directly add a trait in the object of a class without inheriting that trait into the class. We can add a trait in the object instance by using with keyword.
Syntax:
val object_name = new Class_name with Trait_Name;
Example:
// Scala program to illustrate how to add a trait to an object instance 
class MyClass{}
trait MyTrait
{
    println("Welcome to MyTrait");
}
object Main 
{
    // Main method
    def main(args: Array[String])
    {        
        // Here MyTrait is added to the object instance of MyClass
        val obj = new MyClass with MyTrait;
    }
}
Output:
Welcome to MyTrait

Inheritance in Scala

When a class inherits from another, it means it extends another. We use the ‘extends’ keyword for this. The class that extends is the subclass, the child class, or the derived class. The other class is the superclass, the parent class, or the base class.
Syntax of Scala Inheritance
To carry out Scala inheritance, we use the keyword ‘extends’:
class Student extends Person(){
/*your code goes here*/
}
Examples :
class Person{
  var SSN:String="999-32-7869"
}
 class Student extends Person{
   var enrolment_no:String="0812CS141028"
 }
object Inheritance {
  def main(args:Array[String]): Unit ={
    var stud = new Student;
    println("SSN: "+stud.SSN)
    println("Enrolment Number: "+stud.enrolment_no)
  }
}
//Output
SSN: 999-32-7869
Enrolment Number: 0812CS141028

To carry out Scala inheritance, we use the keyword ‘extends’ and 'with':
trait Person{
  var SSN:String="999-32-7869"
}
trait Government{
  var voterID:Int = 12342
}
 class Student extends Person with Government {
   var enrolment_no:String="0812CS141028"
 }
object Inheritance {
  def main(args:Array[String]): Unit ={
    var stud = new Student;
    println("SSN: "+stud.SSN)
    println("Enrolment Number: "+stud.enrolment_no)
    println("Voter ID number : " +stud.voterID)
  }
}
//Output
SSN: 999-32-7869
Enrolment Number: 0812CS141028
Voter ID number : 12342

Abstract Classes in Scala
Abstraction is the process to hide the internal details and showing only the functionality. In Scala, abstraction is achieved by using an abstract class.
In Scala, an abstract class is constructed using the abstract keyword. It contains both abstract and non-abstract methods and cannot support multiple inheritances. A class can extend only one abstract class.
Syntax:
abstract class class_name
{
// code..
}
The abstract methods of abstract class are those methods which do not contain any implementation. Or in other words, the method which does not contain body is known as an abstract method.
Example:
// Abstract class
abstract class mylife
{
      
    // abstract method
    def details()
}
 
// UVPM class extends abstract class
class UVPM extends mylife
{
    def details()
    {
        println("Life: UVPM")
        println("Topic name: Abstract class in Scala")
    }
}
 
object Main 
{
    // Main method
    def main(args: Array[String]) 
    {
        // objects of UVPM class
        var obj = new UVPM()
        obj.details()
    }
}

Like Java, in Scala, we are not allowed to create the instance of the abstract class.
In Scala, an abstract class can also contain fields. These fields are accessed by the abstract class methods and by the methods of the class which inherit abstract class(like inheritance).
Like Java, In Scala, an abstract class can also contain a constructor and a constructor of an abstract class is called when an instance of a inherited class is created. As shown in the below program.
// Abstract class with constructor and the constructor conatin two arguments
abstract class mylife(name: String, topic: String)
{
    def details()
}
 
// UVPM class extends abstract class
class UVPM(name: String, topic: String) extends mylife(name, topic)
{
    def details()
    {
        println("Life : " + name)
        println("Topic name: " + topic)
    }
}
 
object Main 
{
     
    // Main method
    def main(args: Array[String])
    {
         
        // objects of UVPM class
        var obj = new UVPM("UVPM", "Life is a class")
        obj.details()
    }
}

An abstract class can also contain only non- abstract method. This allows us to create classes that cannot be instantiated, but can only be inherited. As shown in the below program.
// Abstract class with non-abstract method
abstract class mylife
{
      
    // Non-abstract method
    def details()
    {
        println("Welcome to UVPM")
    }
}
 
// UVPM class extends abstract class
class UVPM extends mylife{}
 
object Main 
{
     
    // Main method
    def main(args: Array[String])
    {
         
        // objects of UVPM class
        var obj = new UVPM()
        obj.details()
    }
}
//Output:
Welcome to UVPM

In Scala, an abstract class can contain final methods (methods that cannot be overridden).
// Abstract class with the final method
abstract class mylife
{
    final def mymethod()
    {
        println("Final method")
    }
}
 
// UVPM class extends abstract class
class UVPM extends mylife{}
 
object Main 
{
     
    // Main method
    def main(args: Array[String]) 
    {
         
        // objects of UVPM class
        var obj = new UVPM()
        obj.mymethod()
    }
}


Encapsulation
Encapsulation is one of the fundamental concepts in object-oriented programming (OOP). It describes the idea of bundling data and methods that work on that data within one unit
Encapsulation is not only a matter of getter/setter methods or public/private accessor modifiers. In object-oriented programming, encapsulation not only refers to information hiding but it also refers to bundling both the data and the methods (operating on that data) together in the same object. To achieve good encapsulation, there must a clear distinction between those methods you wish to expose to the public (the so called public interface) and the internal state of an object which must comply with its data invariants. In Scala there are many ways to achieve object-oriented encapulation.
For example, one of my preferred is:
trait AnInterface {
  def aMethod(): AType
}
object AnInterface {
  def apply() = new AnHiddenImplementation()                        //exposed to public
  private class AnHiddenImplementation {                                //hidden
    var aVariable: AType = _
    def aMethod(): AType = {
       // operate on the internal aVariable
    }
  }
}
Firstly, define the trait (the public interface) so to make immediately clear what the clients will see. Then write its companion object to provide a factory method which instantiate a default concrete implementation. That implementation can be completely hidden from clients if defined private inside the companion object.

Polymorphism
Polymorphism is an object-oriented programming concept that refers to the ability of a variable, function or object to take on multiple forms.
Three kinds of Polymorphism Scala supports :
Parametric polymorphism
In this function head, it takes a list of A’s, and returns an A. And it doesn’t matter what the A is: It could be Ints, Strings, Oranges, Cars, whatever. Any A would work, and the function is defined for every A that there can be.
def head[A](xs: List[A]): A = xs(0)
head(1 :: 2 :: Nil)
case class Car(make: String)
head(Car("Civic") :: Car("CR-V") :: Nil)
Parametric polymorphism refers to when the type of a value contains one or more (unconstrained) type variables, so that the value may adopt any type that results from substituting those variables with concrete types.
Subtype polymorphism
Let’s think of a function plus that can add two values of type A:
def plus[A](a1: A, a2: A): A = ???
Depending on the type A, we need to provide different definition for what it means to add them. One way to achieve this is through subtyping.
trait Plus[A] {
    def plus(a2: A): A
}
def plus[A <: Plus[A]](a1: A, a2: A): A = a1.plus(a2)
We can at least provide different definitions of plus for A. But, this is not flexible since trait Plus needs to be mixed in at the time of defining the datatype. So it can’t work for Int and String.
Ad-hoc polymorphism
The third approach in Scala is to provide an implicit conversion or implicit parameters for the trait.
trait Plus[A] {
         def plus(a1: A, a2: A): A
       }
def plus[A: Plus](a1: A, a2: A): A = implicitly[Plus[A]].plus(a1, a2)
This is truely ad-hoc in the sense that
·                   we can provide separate function definitions for different types of A
·                  we can provide function definitions to types (like Int) without access to its source code
·            the function definitions can be enabled or disabled in different scopes


No comments:

Post a Comment

Use filter method to filter a Scala collection

Use filter method to filter a Scala collection To use filter on your collection, give it a predicate to filter the collection elements as...