Search code examples
scalapolymorphismtypeclassimplicitvalue-class

Scala implicit class based on type class


implicit class IntIncrement(val underlying: Int) extends AnyVal {
    def increment(): Int = underlying + 1
}

This is valid and allows me to do something like 1.increment()

I want to be able to constrain a type parameter to have this .increment() method on it, so I started doing this:

trait Increment[T] {
    def increment(value: T): T
}

object Increment {
    implicit val implInt: Increment[Int] = new Increment[Int] {
        def increment(value: Int): Int = {
            value + 1
        }
    }
}

def increment[T](value: T)(implicit valueIntDec: Increment[T]): T = {
    valueIntDec.increment(value)
}

issue is, this increment method only allows for increment(1) instead of 1.increment()

is there any way to create an implicit class for any T that has an implicit of Increment[T]

implicit class ImplicitIncrement[T](val underlying: implicit Increment[T]) extends AnyVal {
    def increment(): T = increment(underlying)
}

something like this ^^


Solution

  • You can do that, just without AnyVal:

    implicit class TIncrement[T : Increment](val underlying: T)  {
        def increment: T = implicitly[Increment[T]].increment(underlying)
    }
    

    But I am not sure I see the value in delegating to the type class here: rather than creating a type class implementation for every "incrementable" type, why not just have separate implicit classes that would just increment directly?

    like

    implicit class I(val v: Int) extends AnyVal { def increment = v + 1 }
    implicit class L(val v: Long) extends AnyVal { def increment = v + 1 }
       // etc
    

    UPDATE Actually, you can do that with type class and AnyVal too:

    implicit class TIncrement[T](val underlying: T) extends AnyVal  {
        def increment(implicit inc: Increment[T]): T = inc.increment(underlying)
    }