Home > Software design >  The difference between Scala type bound and generalized type constraints
The difference between Scala type bound and generalized type constraints

Time:01-29

Is there any sufficient difference between constraints of two method at the trait Foo?

trait Foo[A] {
    def barWithTypeBound[B <: A]: B

    def barWithGeneralizedTypeConstraint[B](implicit ev: B <:< A): B
  }

CodePudding user response:

Sometimes it is easier to produce an evidence at call site than provide the evidence through all intermediate layers, e.g.

trait Flattenable[F[_]] {

  def flatten[A](ffa: F[F[A]]): F[A]
}

extension [F[_], A](fa: F[A])
  def flatten[B](using A <:< F[B], F: Flattenable[F]): F[B] =
    F.flatten(fa)

To implement this extension without <:< I would have to change the definition of fa:

extension [F[_], A](fa: F[F[A]])
  def flatten[B](using F: Flattenable[F]): F[B] =
    F.flatten(fa)

which is possible here but not in every case. Another example would be something like:

class Wrapper[A](value: A):

  def get: A = value

  def isNatural(using: A <:< Int): Boolean = value >= 0

  def isTrue(using A <:< Boolean): Boolean = value

which allows caller to call the method only of A is of particular type. (But again, you could solve these with specialized extension methods and normal constraints). I was able to define parametric type in one place, and slap an additional constraint on it later on. If I would need that constrain from the start, I would just use a type bound.

Usually, there is no need to make some method (or implicit, or given) available or not based on the type. And it only proves that some particular case is true, so it wouldn't work well with co- and contravatiance. And, it requires you to create a dummy object. So with exception of a few cases where such "hack" is useful normal constrains are preferred.

In your example there is no difference between the 2 methods, except the second one would have to pass and additional object as a parameter.

  •  Tags:  
  • Related