The type class pattern in Scala involves defining a trait such as:
trait Show[T] {
def show(obj: T): String
}
Then you can define instantiations of this type class as such:
object Show {
implicit val string = new Show[String] {
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
def show(obj: Boolean): String = obj.toString
}
}
The advantage of defining these instantiations for basic types in the companion object is that they are automatically in scope whenever the type class is concerned (roughly).
Functionally it would appear defining the instantiation as an implicit val or an implicit object does not change much.
Is there a difference? Is one way better than the other?
There is actually more than the type names between val
and object
.
You know, object
in Scala is something like a singleton in Java.
Maybe you thought that both string
and BooleanShow
are in an object
not a class
so they have no difference, but that's not true.
They are val
and object
no matter what.
Try this in Scala REPL.
trait Show[T] {
def show(obj: T): String
}
object Show {
println("!! Show created")
implicit val string = new Show[String] {
println("!! string created")
def show(obj: String): String = obj
}
implicit object BooleanShow extends Show[Boolean] {
println("!!BooleanShow created")
def show(obj: Boolean): String = obj.toString
}
}
If only the definition is done, then no println
s are executed afterwards, since Show
is a singleton in effect. It's not created yet.
Next, execute Show
in Scala REPL.
scala> Show
!! Show created
!! string created
res0: Show.type = Show$@35afff3b
You see, println
s in Show
and Show.string
were called, but the one in Show.BooleanShow
was not.
You can execute Show.BooleanShow
next in Scala REPL.
scala> Show.BooleanShow
!!BooleanShow created
res1: Show.BooleanShow.type = Show$BooleanShow$@18e419c5
Show.BooleanShow
was initialized at last. It is a singleton, so it is lazy.
Basically, your question is the same as val and object inside a scala class? except that your val
and object
are defined in an object
, but the linked question tries to find differences val
and object
defined in a class
and the method in val
uses reflection (but yours uses overriding, so no reflection is involved). implicit
basically does not make difference in what they are.
I think you already know the difference between class
and object
. Further information can be found in the linked question.
Since they say always to use explicit types for implicits, prefer val over object.
Compare Why can't Scala find my typeclass instance defined implicitly in the companion object, when the typeclass is not in a dedicated source file? where it makes a difference.
Make it lazy if necessary.
Elaboration:
scala> trait T
defined trait T
scala> object X { implicitly[T] ; object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; object O extends T }
^
scala> object X { implicitly[T] ; implicit object O extends T }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T }
^
scala> object X { implicitly[O.type] ; implicit object O extends T }
defined object X
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
<console>:8: error: could not find implicit value for parameter e: T
object X { implicitly[T] ; implicit object O extends T ; implicit def y = O }
^
scala> object X { implicitly[T] ; implicit object O extends T ; implicit def y: T = O }
defined object X
The inferred type of O
is the singleton type O.type
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With