scalacontext-bound

Scala context bounds


Using context bounds in scala you can do stuff like

trait HasBuild[T] {
  def build(buildable: T): Something
}

object Builders {
  implict object IntBuilder extends HasBuild[Int] {
    override def build(i: Int) = ??? // Construct a Something however appropriate
  }
}

import Builders._
def foo[T: HasBuild](input: T): Something = implicitly[HasBuild[T]].build(1)
val somethingFormInt = foo(1)

Or simply

val somethingFromInt = implicitly[HasBuild[Int]].build(1)

How could I express the type of a Seq of any elements that have an appropriate implicit HasBuild object in scope? Is this possible without too much magic and external libraries?

Seq[WhatTypeGoesHere] - I should be able to find the appropriate HasBuild for each element

This obviously doesn't compile:

val buildables: Seq[_: HasBuild] = ???

Solution

  • Basically I'd like to be able to handle unrelated types in a common way (e.g.: build), without the user wrapping them in some kind of adapter manually - and enforce by the compiler, that the types actually can be handled. Not sure if the purpose is clear.

    Something you can do:

    case class HasHasBuild[A](value: A)(implicit val ev: HasBuild[A])
    object HasHasBuild {
      implicit def removeEvidence[A](x: HasHasBuild[A]): A = x.value
      implicit def addEvidence[A: HasBuild](x: A): HasHasBuild[A] = HasHasBuild(x)
    }
    

    and now (assuming you add a HasBuild[String] for demonstration):

    val buildables: Seq[HasHasBuild[_]] = Seq(1, "a")
    

    compiles, but

    val buildables1: Seq[HasHasBuild[_]] = Seq(1, "a", 1.0)
    

    doesn't. You can use methods with implicit HasBuild parameters when you have only a HasHasBuild:

    def foo1[A](x: HasHasBuild[A]) = {
      import x.ev // now you have an implicit HasBuild[A] in scope
      foo(x.value)
    }
    
    val somethings: Seq[Something] = buildables.map(foo1(_))