Reputation: 3370
I thought this should work to make a light alternative to type classes but it does not :
trait Summable[T] {
def sumWith(other: T): T
}
implicit class StringSummable(s: String) extends Summable[String]{
def sumWith(other: String): String = s + other
}
def sumAll[T <: Summable[T]](list: List[T]): T = {
list.reduceLeft((sum, element) => sum.sumWith(element))
}
sumAll(List("1","2","3"))
I have this error : inferred type arguments [lang.this.String] do not conform to method sumAll's type parameter bounds [T <: Summable[T]]
Is there a trick to make this work?
Thanks
Upvotes: 1
Views: 1282
Reputation: 44957
Yes, there is a "trick", it's literally a single-character change:
':' -> '%'
from subtyping to "implicit convertibility" bounds:
trait Summable[T] {
def sumWith(other: T): T
}
implicit class StringSummable(s: String) extends Summable[String]{
def sumWith(other: String): String = s + other
}
def sumAll[T <% Summable[T]](list: List[T]): T = {
list.reduceLeft((sum, element) => sum.sumWith(element))
}
sumAll(List("1","2","3"))
Note that this tends to fall apart rather quickly. For example, as soon as you need a zero-ary function that returns an empty String
, you are essentially out of luck with this approach, whereas it is trivial with a typeclass (as Monoid[T]
shows). Without it, you can't even define sumAll
properly, because it doesn't work on empty lists.
Note that the historical development so far has been away from implicit conversions, and towards the typeclasses, not the other way round.
Upvotes: 3