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