0
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 ^^

Dmytro Mitin
  • 48,194
  • 3
  • 28
  • 66
doliphin
  • 752
  • 6
  • 22
  • You're close. `(implicit val underlying: Increment[T])` should be instead of `(val underlying: implicit Increment[T])` – Dmytro Mitin Dec 22 '22 at 06:29

1 Answers1

2

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)
}
Dima
  • 39,570
  • 6
  • 44
  • 70
  • *"why not just have separate implicit classes"* I guess having a type class, its instances and the only implicit class defining a syntax via delegation to the type class (rather than having separate implicit classes/implicit conversions) is a common pattern. For example if you'd like to define an instance for `List[A]` having an instance for `A`, with a type class this would be easy e.g. `implicit def listInc[A: Increment]: Increment[List[A]] = new Increment[List[A]] { override def increment(value: List[A]): List[A] = value.map(_.increment()) }`. – Dmytro Mitin Dec 22 '22 at 06:50
  • 1
    But with implicit classes this would be harder: `implicit class Lst[A](val v: List[A])(implicit ev: A => /*A*/ {def increment(): A})...` seems not to work. – Dmytro Mitin Dec 22 '22 at 06:50
  • @DmytroMitin though, I am still not sure what is the problem with `implicit class X[A](val x: List[A]) { def increment(implicit _: TIncrement[A]) = x.map(x.increment) } ` – Dima Dec 22 '22 at 14:04
  • 1
    I guess `(implicit _: TIncrement[A])` can't be correct. With implicit class you don't define an implicit instance of type `TIncrement[A]`, you define an implicit conversion `A => TIncrement[A]`. – Dmytro Mitin Dec 22 '22 at 22:42
  • Yeah, I see your point now. – Dima Dec 23 '22 at 02:30
  • Although what you proposed with implicit conversions/implicit classes was close to a pattern different from type class, namely magnet https://scastie.scala-lang.org/DmytroMitin/sxUpSmC7S8KUXJiEaXCWXA/1 https://stackoverflow.com/questions/74203834/group-typeclass-instances-by-type-parameter – Dmytro Mitin Dec 23 '22 at 20:54