xm22
xm22

Reputation: 89

Automatic imports from multiple implicit objects

I just found the type class concept of Scala and like it actually very much. The problem I have it that all examples I found put the type classes (objects) under one object (Like here: http://danielwestheide.com/blog/2013/02/06/the-neophytes-guide-to-scala-part-12-type-classes.html)

Maybe this is wrong but I am a friend of having one file per class. So what I like to do is to put the type classes into several files which would mean that each implementation needs to be put into a seperate object. This now leads to the "problem" that I need to import every single implementation manually. To clarify better here a small example:

package sth

import sth.like.Like
import sth.like.StringLike._
import sth.like.IntLike._

object Application extends App {
    def t[T](arg: T)(implicit l: Like[T]) = {
        l.print(arg)
    }

    t(1)
    t("Blub")
}

-

package sth.like

trait Like[T] {
    def print(arg: T)
}

-

package sth.like

object IntLike {
    implicit object LikeIntLike extends Like[Int] {
        def print(arg: Int): Unit = println(s"INT $arg")
    }
}

-

package sth.like

object StringLike {
    implicit object LikeStringLike extends Like[String] {
        override def print(arg: String): Unit = println(s"STRING: $arg")
    }
}

This works so far. I know, the wildcard import in Application is not necessary but that is not the point. As you can see I need to import both StringLike and IntLike in Application because otherwise these are not available for the Application object.

So is it possible to do this in a generic way or is it completely bad practise to do it this way?

Upvotes: 3

Views: 866

Answers (2)

xm22
xm22

Reputation: 89

thank you very much for your answer. But I also would need to add new type classes manually to the Implicits, wouldn't I?

Couldn't I use then package objects for simplicity reasons like here:

http://naildrivin5.com/scalatour/wiki_pages/PackageObjects/

?

I mean this part:

package opower {
   package object controller {
       type Secured = org.springframework.security.access.annotation.Secured
       type Controller = org.springframework.stereotype.Controller
       ...
   }
}

Since it seems that there is no dynamic way I could just put all type classes into the controller object and could this then import.

Or do I missunderstand the package object?

Upvotes: 0

Łukasz
Łukasz

Reputation: 8663

You could put your implicits inside traits, not objects

trait IntLike {
  implicit object LikeIntLike extends Like[Int] {
    def print(arg: Int): Unit = println(s"INT $arg")
  }
}

And then have object with the same name, extending this trait, which would give you what you had earlier, you can import each implicit individually.

object IntLike extends IntLike

You can do the same for all other instances of your typeclass:

trait StringLike {
  implicit object LikeStringLike extends Like[String] {
    override def print(arg: String): Unit = println(s"STRING: $arg")
  }
}

object StringLike extends StringLike

And in another file, you can combine all traits together like this:

object Implicits extends StringLike with IntLike

and import just the Implicits object if you want all your implicits in scope.

package sth

import sth.like.Like
import sth.like.Implicits._

object Application extends App {
  def t[T](arg: T)(implicit l: Like[T]) = {
    l.print(arg)
  }

  t(1)
  t("Blub")
}

Optionally, you can mixin traits you need

object Application extends App with StringLike with IntLike { ... }

or even do

trait Implicits extends StringLike with IntLike
object Implicits extends Implicits

object Application extends App with Implicits { ... }

Upvotes: 6

Related Questions