Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Is it better to use vals or object when providing instances of a typeclass in Scala

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?

like image 874
jedesah Avatar asked Aug 26 '14 21:08

jedesah


2 Answers

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 printlns 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, printlns 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.

like image 113
Naetmul Avatar answered Dec 15 '22 06:12

Naetmul


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.

like image 36
som-snytt Avatar answered Dec 15 '22 04:12

som-snytt