Trait Basics
- Traits and Java interfaces
- Traits as Mixins - "orthogonal" functionality
Traits as interfaces
FILE : traits1.StarterTraits1Demo
As a standard Java 7 Interface
Scala:
trait StandardJava7Interface{
def methodToImplement(arg:String):Unit
}
Java:
public interface jug.lodz.workshops.starter.traits1.StandardJava7Interface {
public abstract void methodToImplement(java.lang.String);
}
As an interface with default method (Java8)
Scala implements this as a static method in interface (possible from java 8)
trait StandardJava8Interface{
def methodToImplement(arg:String):Unit={
println(s"hello $arg")
}
}
Instead of default methods scala implements body in static methods - performacne reasons : http://www.scala-lang.org/blog/2016/07/08/trait-method-performance.html
public interface jug.lodz.workshops.starter.traits1.StandardJava8Interface {
public static void methodToImplement$(jug.lodz.workshops.starter.traits1.StandardJava8Interface, java.lang.String);
public void methodToimplement(java.lang.String);
public static void $init$(jug.lodz.workshops.starter.traits1.StandardJava8Interface);
}
As an Interface with fields
Similarly to previous one - Scala implements this as a static method in interface (possible from java 8).
With possibility of adding fields we can now add fully independent orhogonal functionality like logging.
Scala:
trait Logger{
def debug(message:String):Unit
def info(message:String):Unit
}
class ConsoleLogger extends Logger{
override def debug(message: String): Unit = println(s"[DEBUG] : $message")
override def info(message: String): Unit = println(s"[INFO] : $message")
}
trait HasLogger{
val logger= new ConsoleLogger
}
class SomeClass extends HasLogger
Decompiled:
Compiled from "StarterTraits1Demo.scala"
public class jug.lodz.workshops.starter.traits1.SomeClass implements jug.lodz.workshops.starter.traits1.HasLogger {
public jug.lodz.workshops.starter.traits1.ConsoleLogger logger();
public void jug$lodz$workshops$starter$traits1$HasLogger$_setter_$logger_$eq(jug.lodz.workshops.starter.traits1.ConsoleLogger);
public jug.lodz.workshops.starter.traits1.SomeClass();
}
Self aware types
FILE: traits1.SelfAwareTypesDemo
Self aware types allow us to join two independent types family. In the example below we can create special DateLogger when know that trait will be mixed into Clock family
trait Clock{
def currentDate:String
}
trait DateLogger extends BaseLogger { this:Clock =>
override def debug(message: String): Unit = super.debug(message + " at "+ currentDate)
}
Exact clock implementation is hidden.
Exercise
FILE : jug.lodz.workshops.starter.traits1.exercises.StarterTraits1ExerciseSpec
1) Implement Event Store
Complete account trait so it stores events in First-In-Last-Out order.
2) Use self-aware type to add date to stored event
There is a second type hierarchy created -> Calendar . Mix it with event store to create DateStore trait which adds current date to events