• Menu
  • Skip to primary navigation
  • Skip to main content
  • Skip to primary sidebar

JavaBeat

Java Tutorial Blog

  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)
  • Java
    • Java 7
    • Java 8
    • Java EE
    • Servlets
  • Spring Framework
    • Spring Tutorials
    • Spring 4 Tutorials
    • Spring Boot
  • JSF Tutorials
  • Most Popular
    • Binary Search Tree Traversal
    • Spring Batch Tutorial
    • AngularJS + Spring MVC
    • Spring Data JPA Tutorial
    • Packaging and Deploying Node.js
  • About Us
    • Join Us (JBC)

Traits in Scala- Advanced concepts

July 6, 2012 //  by Mohamed Sanaulla//  Leave a Comment

In our previous article we covered very basic concepts on traits. In this article we will expand on our initial work and explore the inherent power of traits.

As we said here just like the Interfaces traits can have abstract methods. Also traits can extend other traits just like Interfaces can extend other interfaces.

also read:

  • Primary and Auxiliary Constructors in Scala
  • Traits in Scala
  • Java HelloWorld vs Scala HelloWorld
[code lang=”java”] trait Reader{
def read(source:String):String
}

trait StringReader extends Reader {
override def read(source:String) = {
Source.fromString(source).mkString
}
}
[/code]

We have seen previously about adding trait to the class declaration, but that’s not the only way to add a trait. One can mix in a trait during the object creation as well. But before that lets modify the Reader trait to make the method read to return some default string.

Now lets look at an example to mixin a trait while creating object:
[code lang=”java”] class Person(var name:String, var age:Int){
def getDetails = name+ " "+ age
}

class Student(name:String, age:Int, var moreDetails:String)
extends Person(name,age) with Reader{

override def getDetails = {

val details = read(moreDetails)
"Student details\n"+name+
" "+age+"\n"+"More: "+details

}

}
[/code] Lets create an instance of above Student class without including the StringReader trait.
[code lang=”java”]

object Main extends App{

val student1 = new Student("Sana", 20,
"About the student")

println(student1.getDetails)
}

[/code] The output would be:
[code lang=”java”] Student details
Sana 20
More: DEFAULT
[/code] Really not useful, the Reader trait is not enough, so we make use of adding a trait during object creation:
[code lang=”java”] object Main extends App{

val student1 = new Student("Sana", 20,
"About the student") with StringReader

println(student1.getDetails)
}
[/code]

The output:
[shell] Student details
Sana 20
More: About the student
[/shell]

Now we have more meaningful information and not the default implementation. Traits can also have fields- fields can be concrete and abstract. If an initial value is provided for the field in the trait then it becomes a concrete field, otherwise it is an abstract field, something like:
[code lang=”java”] import scala.io.Source
trait Reader{
var source = "DEFAULT"
def read = source
}

trait StringReader extends Reader {

override def read = {
Source.fromString(source).mkString
}

}

class Person(var name:String, var age:Int){
def getDetails = name+ " "+ age
}

class Student(name:String, age:Int, moreDetails:String)
extends Person(name,age) with Reader{

source = moreDetails

override def getDetails = {
val details = read
"Student details\n"+name+" "+age+"\n"+"More: "+details
}
}

object Main extends App{

val student1 = new Student("Sana", 20,
"About the student") with StringReader

println(student1.getDetails)
}
[/code] We just edited the trait and moved the parameter for read method into the field for the trait. And in the class Student we assign a new value to the source field in the trait.

Layering Traits

One can chain the traits such that one trait can invoke another version of the same method in a different trait. Lets add 2 more traits- FileReader and UrlReader. FileReader would read from a file and UrlReader would read content from a given URL.
[code lang=”java”] trait FileReader extends Reader{

override def read(source:String) = {
Source.fromFile(source,"UTF-8").mkString
}
}

trait UrlReader extends Reader{

override def read(source:String) = {
Source.fromURL(super.read(source),"UTF-8").mkString
}
}
[/code] Interesting to see super.read(source) in the UrlReader trait. Does that mean it inokves the read(source) in Reader trait? We wouldn’t expect anything useful from the read(source) version of Reader method. Instead, super.read(source) calls the next trait in the trait hierarchy, which depends on the order in which the traits are added. The traits are processed starting with the last one. Lets see how this makes sense:
[code lang=”java”] object Main extends App{

//case 1
val student2 = new Student("Stud1",20, "/tmp/url")
with FileReader with UrlReader

println(student2.getDetails)

//case 2
val student3 = new Student("Stud2",20,"https://javabeat.net")
with StringReader with UrlReader

println(student3.getDetails)
}
[/code] In the case 1 we add FileReader and UrlReader traits. When UrlReader invokes super.read(source), the read(source) from the FileReader is invoked and you would expect to have a URL in the /tmp/url file.
In the case 2 we add StringReader and UrlReader traits. When the UrlReader invokes super.read(source), the read(source) from the StringReader is invoked.

The example above seems pretty naive and can be implemented in a more concise way. I havent been able to come up with a better example. But I hope I have been able to convey the concept though.

Another interesting concept to explore is how the traits are mapped to the classes which the JVM can consume.
A trait with abstract method:
[code lang=”java”] trait Reader{
def read(source:String):String
}
[/code] translates to a usual Interface in Java
[code lang=”java”] Compiled from "TraitTrans.scala"
public interface Reader {
public abstract java.lang.String read(java.lang.String);
}
[/code]

A trait with method definition would translate into a Interface and a abstract class which has the implementations in the trait moved into static methods. Something like
[code lang=”java”] trait Reader{
def read(source:String):String
}

trait StringReader extends Reader{
import scala.io.Source
def read(source:String) =
Source.fromString(source).mkString
}
[/code] would create StringReader.class and StringReader$class.class files where in the StringReader.class is the interface and StringReader$class.class is an abstract class with the implementations in the static methods
[code lang=”java”] mohamed@mohamed-Aspire-4710:~/scalaP$ javap -c StringReader.class
Compiled from "TraitTrans.scala"
public abstract class StringReader$class {
public static java.lang.String read(StringReader, java.lang.String);
Code:
0: getstatic #11 // Field scala/io/Source$.MODULE$:Lscala/io/Source$;
3: aload_1
4: invokevirtual #16 // Method scala/io/Source$.fromString:(Ljava/lang/String;)Lscala/io/Source;
7: invokeinterface #22, 1 // InterfaceMethod scala/collection/TraversableOnce.mkString:()Ljava/lang/String;
12: areturn

public static void $init$(StringReader);
Code:
0: return
}
[/code] One can make out that the companion class generated contains the method implementations. Here is a superb description of how the traits and classes extending traits get translated to the classfiles for the JVM.

These are few concepts which are worth learning as part of Traits. Another important concept is the Trait construction order and Self Types which I might cover in future posts.

Category: ScalaTag: scala, scala traits

About Mohamed Sanaulla

In his day job he works on developing enterprise applications using ADF. He is also the moderator of JavaRanch forums and an avid blogger.

Previous Post: « Traits in Scala
Next Post: Using Apply and Unapply Methods in Scala »

Reader Interactions

Leave a Reply Cancel reply

Your email address will not be published. Required fields are marked *

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Primary Sidebar

Follow Us

  • Facebook
  • Pinterest

FEATURED TUTORIALS

np.zeros

A Complete Guide To NumPy Functions in Python For Beginners

What is new in Java 6.0 Collections API?

The Java 6.0 Compiler API

Introductiion to Jakarta Struts

What’s new in Struts 2.0? – Struts 2.0 Framework

JavaBeat

Copyright © by JavaBeat · All rights reserved
Privacy Policy | Contact