Understanding extensions method in Scala
Extension Method in Scala
import scala.concurrent.duration._
class SampleActor extends TaskExecutorBase {
val taskTimeout = 10.seconds
def doTask(task: Task): Unit = {
println("Sample task start.")
...
}
}
First time looking at this code, I was wondering why an Integer can have method seconds
.
val taskTimeout = 10.seconds
It’s so magic.
But after looking for awhile, I found out the reason.
It’s a thing I did everyday Implicit Conversion
An implicit conversion from type S to type T is defined by an implicit value which has function type S => T, or by an implicit method convertible to a value of that type.
Implicit conversions are applied in two situations:
- If an expression e is of type S, and S does not conform to the expression’s expected type T.
- In a selection e.m with e of type T, if the selector m does not denote a member of T.
I always use the first situation for serialize from json to case class.
And as above it’s the second one.
Let’s do an example:
case class User(email: String, averagePoint: Double)
case class Course(name: String, point: Double)
val courses = List( Course("Scala", 80), Course("PHP", 90), Course("Javascript", 100))
val points = courses.map(_.point)
// We need to get average point of this courses for User
User("someone@septech.jp", points.sum/points.length)
Then we can do like that.
object ExtendedList {
implicit def toExtendedList(xs: List[Double]) = new {
def avg = xs.sum/xs.length
}
}
//...Other class
import ExtendedList._
val user = User("someone@septech.jp", points.avg) // More expressive
Nothing magic here!
When we say points.avg
, compiler will look for an implicit conversion, and in this case that is function toExtendedList()
which was imported from object ExtendedList
.
Then we have a “looking good” source code.
But it’s not finish.
We are force compiler to infer a structural type for the toExtendedList
, meaning that any invocations of avg
will be done using reflection (a performance killer).
So what is Structural type
?
A structural type system (or property-based type system) is a major class of type system, in which type compatibility and equivalence are determined by the type’s actual structure or definition, and not by other characteristics such as its name or place of declaration.
Using Structural type
is slow because in runtime, compiler need to use reflect method to check which type was used, it’s not good for performance.
Instead of that we can use as bellow
class ExtendedList(xs: List[Double]) {
def avg: Double = xs.sum/xs.length
}
object ExtendedList {
implicit def toExtendedList(list: List[Double]) = new ExtendList(list)
}
Now we’re using convert function from List
to ExtendList
which is implicit method toExtendedList()
.
This case Nominal type
was used, it’s determined by explicit declarations and/or the name of the type and no need runtime type checking.
Someone did a comparision between these two type: Link.
Back to the issue from beginning of this post, it’s time for you to look into scala.concurrent.duration
package and see what’s happening 😉
Main idea here Pimp My Library, it was written by Martin Odersky.
Thanks for reading.
Reference:
StackOverFlow
Nominal type
Structural type