I'm reading ScalaZ tutorial and now I'm on the section of Yes-No type class. Eventual goal is to get 1.truthy to return true. Here is the implementation of the typeclass:
trait CanTruthy[A] { self =>
/** #return true, if `a` is truthy. */
def truthys(a: A): Boolean
}
object CanTruthy {
def apply[A](implicit ev: CanTruthy[A]): CanTruthy[A] = ev
def truthys[A](f: A => Boolean): CanTruthy[A] = new CanTruthy[A] {
def truthys(a: A): Boolean = f(a)
}
}
trait CanTruthyOps[A] {
def self: A
implicit def F: CanTruthy[A]
final def truthy: Boolean = F.truthys(self)
}
object ToCanIsTruthyOps {
implicit def toCanIsTruthyOps[A](v: A)(implicit ev: CanTruthy[A]) =
new CanTruthyOps[A] {
def self = v
implicit def F: CanTruthy[A] = ev
}
}
implicit val intCanTruthy: CanTruthy[Int] = CanTruthy.truthys({
case 0 => false
case _ => true
})
Looks a little scary to me. We introduced 2 new traits to achieve that. But we can achieve the same just by using implicit classes:
trait CanTruthy {
def truthy: Boolean
}
object CanTruthy{
implicit class CanTruthyInt(i: Int) extends CanTruthy{
override def truthy: Boolean = i match {
case 0 => false
case _ => true
}
}
}
Looks the same to me. So why do we need to use the way in the tutorial? What kind of things I missed? Can you explain what is the difference?
I think the problem here is a misreading of the scope of this sentence:
Eventual goal is to get 1.truthy to return true.
This is what we're trying to do with the CanTruthyOps stuff, but it's not the goal of the CanTruthy type class, and more generally syntactic concerns like this aren't the goal of type classes.
The goal of type classes is to allow us to constrain types in a simple, flexible, compositional way. The type parameter-less CanTruthy approach doesn't really support the simple part or the flexible part or the compositional part very nicely (arguably the implementation of type classes in Scala isn't very simple either, but it's at least a little simpler and definitely more flexible and compositional).
Take this method from the tutorial, for example (lightly modified to avoid the Any):
// Type class style
def truthyIf[A: CanTruthy, B](cond: A)(ifyes: => B)(ifno: => B): B =
if (cond.truthy) ifyes else ifno
If you wanted to translate this into your type parameter-less style, at first things seem pretty good:
// Parameterless style
def truthyIf[B](cond: CanTruthy)(ifyes: => B)(ifno: => B): B =
if (cond.truthy) ifyes else ifno
But now suppose that you needed to keep the original type around. There are lots of reasons this might be necessary—you might want to sort a collection of values with scala.Ordering before you check the truthiness of one of them, for example, or you might have a variation of this method where the original type is also the return type (in the type class style here):
// Type class style
def truthyOrElse[A: CanTruthy](cond: A)(ifno: => A): A =
if (cond.truthy) cond else ifno
Now the translation is less fun:
// Type parameter-less style
def truthyOrElse[A <% CanTruthy](cond: A)(ifno: => A): A =
if (cond.truthy) ifyes else ifno
Where the funky <% thing is syntactic sugar for an implicit parameter:
// Type parameter-less style (desugared)
def truthyOrElse[A](cond: A)(ifno: => A)(implicit evidence$1: A => CanTruthy): A =
if (cond.truthy) cond else ifno
But the : in the type class style is also syntactic sugar:
// Type class style, desugared
def truthyOrElse[A](cond: A)(ifno: => A)(implicit evidence$2: CanTruthy[A]): A =
if (cond.truthy) cond else ifno
Note that these methods look almost identical—in both you're writing a method that requires some implicit evidence (at compilation time) that A is truthy. In the type parameter-less style this evidence is an implicit conversion, while in the type class style it's an implicit value of a generic type.
There are several advantages to the latter approach. One kind of abstract one is that it allows us to separate the "here's some evidence that I know how to do X for this type" concern from the purely syntactic "I can call .x on this thing" concern. Sure, this separation requires some extra machinery (two traits instead of one), but keeping a clean line between the syntactic and semantic issues is arguably worth it.
Another (related) advantage is that the type class can be more efficient, since it allows us to forgo the syntax, and therefore also the extra allocation it involves:
// Type class style, no syntax
def truthyOrElse[A](cond: A)(ifno: => A)(implicit ev: CanTruthy[A]): A =
if (ev.truthys(cond)) cond else ifno
Another advantage comes up in cases where the operation you're trying to provide evidence about involves more than one value:
trait Addable[A] {
def plus(a: A, b: A): A
}
object Addable {
implicit val intAddable: Addable[Int] = new Addable[Int] {
def plus(a: Int, b: Int): Int = a + b
}
}
There's just no nice way to do this kind of thing as an Int => Addable implicit conversion.
The type class approach similarly handles cases where you have multiple types that you need your operation to work on, etc., while the type parameter-less approach doesn't really (at least not in any reasonably clean way).
So to sum up: if you just want some nice enrichment methods that you're generally using in situations where you have concrete types, the type parameter-less approach is totally reasonable and may involve a little less code. If you want to be able to abstract over types that support some operation in an efficient, flexible, generic, and reasonably elegant way, write a type class.
Assume there are such two traits:
trait Fooer[-T] {
def foo(x: T): Unit
}
trait CanFoo[-T] {
def fooer: Fooer[T]
}
And a function:
def bar[T: CanFoo](x: T) = {
implicitly[CanFoo[T]].fooer.foo(x)
}
Everything works so far. However, I was stuck when trying to make bar work recursively on collection types like Seq[T] (i.e. bar[Seq[T]](seq) recursively calls bar[T] on seq's elements). I can't do implicit object CanFooSeq extends CanFoo[Seq[_]] since that would cause the type information of the elements to be lost. (I also tried to make another function def bar[T: CanFoo](seq: Seq[T]) = ..., but that didn't solve the problem either since Seq[T] still isn't being recognized as a Foo-able type.)
Is there any way to solve this problem?
implicit def CanFooSeq[T]: CanFoo[Seq[T]] = new CanFoo[Seq[T]] { def fooer = ... }
(if you want to have it only in case you have CanFoo[T], add the implicit parameter: implicit def CanFooSeq[T: CanFoo]: CanFoo[Seq[T]] = new CanFoo[Seq[T]] { def fooer = ... }) if I understood the question correctly. Note it has to be a def, because objects and vals can't have type parameters, so a new one will be created on each call (which is very unlikely to matter for performance in practice).
I have some code like this:
sealed trait Foo[A] {
def value: A
}
case class StringFoo(value: String) extends Foo[String]
case class IntFoo(value: Int) extends Foo[Int]
I'd like to have a function which can use the A type given a subtype's type parameter.
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
I can't figure out how to declare dostuff in a way that works. The closest thing I can figure out is
def dostuff[B <: Foo[A]](p: Param): A
But that doesn't work because A is undefined in that position. I can do something like
def dostuff[A, B <: Foo[A]](p: Param): A
But then I have to invoke it like dostuff[String, StringFoo](param) which is pretty ugly.
It seems like the compiler should have all the information it needs to move A across to the return type, how can I make this work, either in standard scala or with a library. I'm on scala 2.10 currently if that impacts the answer. I'm open to a 2.11-only solution if it's possible there but impossible in 2.10
Another option is to use type members:
sealed trait Foo {
type Value
def value: Value
}
case class StringFoo(value: String) extends Foo { type Value = String }
case class IntFoo(value: Int) extends Foo { type Value = Int }
def dostuff[B <: Foo](p: Any): B#Value = ???
// Hypothetical invocation
val i: Int = dostuff[IntFoo](param)
val s: String = dostuff[StringFoo](param)
Note that both solutions mainly work around the syntactic restriction in Scala, that you cannot fix one type parameter of a list and have the compiler infer the other.
As you might know, if you have a parameter of type Foo[A], then you can make the method generic in just A:
def dostuff[A](p: Foo[A]): A = ???
Since that might not always be the case, we can try to use an implicit parameter that can express the relationship between A and B. Since we can't only apply some of the generic parameters to a method call (generic parameter inference is all or nothing), we have to split this into 2 calls. This is an option:
case class Stuff[B <: Foo[_]]() {
def get[A](p: Param)(implicit ev: B => Foo[A]): A = ???
}
You can check the types in the REPL:
:t Stuff[IntFoo].get(new Param) //Int
:t Stuff[StringFoo].get(new Param) //String
Another option along the same lines, but using an anonymous class, is:
def stuff[B <: Foo[_]] = new {
def apply[A](p: Param)(implicit ev: B <:< Foo[A]): A = ???
}
:t stuff[IntFoo](new Param) //Int
Here, I've used apply in stead of get, so you can apply the method more naturally. Also, as suggested in your comment, here I've used <:< in the evidence type. For those looking to learn more about this type of generalized type constraint, you can read more here.
You might also consider using abstract type members instead of generic parameters here. When struggling with generic type inference, this often provides an elegant solution. You can read more about abstract type members and their relationship to generics here.
I am rather new to Scala programming, so still figuring out canonical ways to doing something. Lately, I wanted to write a function foo that would only accept a set of types for its only parameter. Think of something like
def foo(x: [Int, String]) = ???
But I couldn't find anything close to the syntax above (which I find most natural to me). Using type Any would loose the compile-side checking and would make it easier for problems to escape into the runtime land.
The best I was able to come up with is something like this:
sealed abstract class Base
case class TypeInt(v: Int) extends Base
case class TypeString(v: String) extends Base
implicit def toTypeInt(v: Int) = TypeInt(v)
implicit def toTypeString(v: String) = TypeString(v)
def foo(x: Base) = x match {
case TypeInt(v) => println("Int: ", v)
case TypeString(v) => println("String: ", v)
}
foo(1)
foo("hello")
(As a side note, I would like to be able to just write implicit case class ... to avoid creating manually the toType* functions but that doesn't compile.)
Is there a simpler way to write a function that accepts a parameter of a set of types in a typesafe manner?
UPDATE: It actually turns out that in my specific case I could just have used method overloading. For some reason it's not possible to use method overloading at all in Scala worksheet which made me think that Scala doesn't have overloading at all. But I was wrong - in regular Scala source it should be possible to use that. There are still some shortcomings of overload usage that are described in the article on Magnet pattern that was mentioned in comments below (e.g. there is no way to overload on type Foo[Type1] and Foo[Type2] because of type erasure in JVM generics.
The magnet pattern feels like overkill here—you can use plain old type classes:
trait Fooable[A] { def apply(a: A): Unit }
implicit object intFooable extends Fooable[Int] {
def apply(a: Int) = printf("Int: %d\n", a)
}
implicit object stringFooable extends Fooable[String] {
def apply(a: String) = printf("String: %s\n", a)
}
def foo[A: Fooable](a: A) = implicitly[Fooable[A]].apply(a)
And then:
scala> foo(1)
Int: 1
scala> foo("hello")
String: hello
Suppose you're worried about collisions after erasure. Let's try some instances for a generic type:
trait Bar[A]
implicit object barIntFooable extends Fooable[Bar[Int]] {
def apply(a: Bar[Int]) = println("A bar of ints.")
}
implicit object barStringFooable extends Fooable[Bar[String]] {
def apply(a: Bar[String]) = println("A bar of strings.")
}
And again:
scala> foo(new Bar[Int] {})
A bar of ints.
scala> foo(new Bar[String] {})
A bar of strings.
Everything works as expected.
I wrote this in scala and it won't compile:
class TestDoubleDef{
def foo(p:List[String]) = {}
def foo(p:List[Int]) = {}
}
the compiler notify:
[error] double definition:
[error] method foo:(List[String])Unit and
[error] method foo:(List[Int])Unit at line 120
[error] have same type after erasure: (List)Unit
I know JVM has no native support for generics so I understand this error.
I could write wrappers for List[String] and List[Int] but I'm lazy :)
I'm doubtful but, is there another way expressing List[String] is not the same type than List[Int]?
Thanks.
I like Michael Krämer's idea to use implicits, but I think it can be applied more directly:
case class IntList(list: List[Int])
case class StringList(list: List[String])
implicit def il(list: List[Int]) = IntList(list)
implicit def sl(list: List[String]) = StringList(list)
def foo(i: IntList) { println("Int: " + i.list)}
def foo(s: StringList) { println("String: " + s.list)}
I think this is quite readable and straightforward.
[Update]
There is another easy way which seems to work:
def foo(p: List[String]) { println("Strings") }
def foo[X: ClassTag](p: List[Int]) { println("Ints") }
def foo[X: ClassTag, Y: ClassTag](p: List[Double]) { println("Doubles") }
For every version you need an additional type parameter, so this doesn't scale, but I think for three or four versions it's fine.
[Update 2]
For exactly two methods I found another nice trick:
def foo(list: => List[Int]) = { println("Int-List " + list)}
def foo(list: List[String]) = { println("String-List " + list)}
Instead of inventing dummy implicit values, you can use the DummyImplicit defined in Predef which seems to be made exactly for that:
class TestMultipleDef {
def foo(p:List[String]) = ()
def foo(p:List[Int])(implicit d: DummyImplicit) = ()
def foo(p:List[java.util.Date])(implicit d1: DummyImplicit, d2: DummyImplicit) = ()
}
To understand Michael Krämer's solution, it's necessary to recognize that the types of the implicit parameters are unimportant. What is important is that their types are distinct.
The following code works in the same way:
class TestDoubleDef {
object dummy1 { implicit val dummy: dummy1.type = this }
object dummy2 { implicit val dummy: dummy2.type = this }
def foo(p:List[String])(implicit d: dummy1.type) = {}
def foo(p:List[Int])(implicit d: dummy2.type) = {}
}
object App extends Application {
val a = new TestDoubleDef()
a.foo(1::2::Nil)
a.foo("a"::"b"::Nil)
}
At the bytecode level, both foo methods become two-argument methods since JVM bytecode knows nothing of implicit parameters or multiple parameter lists. At the callsite, the Scala compiler selects the appropriate foo method to call (and therefore the appropriate dummy object to pass in) by looking at the type of the list being passed in (which isn't erased until later).
While it's more verbose, this approach relieves the caller of the burden of supplying the implicit arguments. In fact, it even works if the dummyN objects are private to the TestDoubleDef class.
Due to the wonders of type erasure, the type parameters of your methods' List get erased during compilation, thus reducing both methods to the same signature, which is a compiler error.
As Viktor Klang already says, the generic type will be erased by the compiler. Fortunately, there's a workaround:
class TestDoubleDef{
def foo(p:List[String])(implicit ignore: String) = {}
def foo(p:List[Int])(implicit ignore: Int) = {}
}
object App extends Application {
implicit val x = 0
implicit val y = ""
val a = new A()
a.foo(1::2::Nil)
a.foo("a"::"b"::Nil)
}
Thanks for Michid for the tip!
If I combine Daniels response and Sandor Murakozis response here I get:
#annotation.implicitNotFound(msg = "Type ${T} not supported only Int and String accepted")
sealed abstract class Acceptable[T]; object Acceptable {
implicit object IntOk extends Acceptable[Int]
implicit object StringOk extends Acceptable[String]
}
class TestDoubleDef {
def foo[A : Acceptable : Manifest](p:List[A]) = {
val m = manifest[A]
if (m equals manifest[String]) {
println("String")
} else if (m equals manifest[Int]) {
println("Int")
}
}
}
I get a typesafe(ish) variant
scala> val a = new TestDoubleDef
a: TestDoubleDef = TestDoubleDef#f3cc05f
scala> a.foo(List(1,2,3))
Int
scala> a.foo(List("test","testa"))
String
scala> a.foo(List(1L,2L,3L))
<console>:21: error: Type Long not supported only Int and String accepted
a.foo(List(1L,2L,3L))
^
scala> a.foo("test")
<console>:9: error: type mismatch;
found : java.lang.String("test")
required: List[?]
a.foo("test")
^
The logic may also be included in the type class as such (thanks to jsuereth):
#annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted")
sealed trait Foo[T] { def apply(list : List[T]) : Unit }
object Foo {
implicit def stringImpl = new Foo[String] {
def apply(list : List[String]) = println("String")
}
implicit def intImpl = new Foo[Int] {
def apply(list : List[Int]) = println("Int")
}
}
def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
Which gives:
scala> #annotation.implicitNotFound(msg = "Foo does not support ${T} only Int and String accepted")
| sealed trait Foo[T] { def apply(list : List[T]) : Unit }; object Foo {
| implicit def stringImpl = new Foo[String] {
| def apply(list : List[String]) = println("String")
| }
| implicit def intImpl = new Foo[Int] {
| def apply(list : List[Int]) = println("Int")
| }
| } ; def foo[A : Foo](x : List[A]) = implicitly[Foo[A]].apply(x)
defined trait Foo
defined module Foo
foo: [A](x: List[A])(implicit evidence$1: Foo[A])Unit
scala> foo(1)
<console>:8: error: type mismatch;
found : Int(1)
required: List[?]
foo(1)
^
scala> foo(List(1,2,3))
Int
scala> foo(List("a","b","c"))
String
scala> foo(List(1.0))
<console>:32: error: Foo does not support Double only Int and String accepted
foo(List(1.0))
^
Note that we have to write implicitly[Foo[A]].apply(x) since the compiler thinks that implicitly[Foo[A]](x) means that we call implicitly with parameters.
There is (at least one) another way, even if it is not too nice and not really type safe:
import scala.reflect.Manifest
object Reified {
def foo[T](p:List[T])(implicit m: Manifest[T]) = {
def stringList(l: List[String]) {
println("Strings")
}
def intList(l: List[Int]) {
println("Ints")
}
val StringClass = classOf[String]
val IntClass = classOf[Int]
m.erasure match {
case StringClass => stringList(p.asInstanceOf[List[String]])
case IntClass => intList(p.asInstanceOf[List[Int]])
case _ => error("???")
}
}
def main(args: Array[String]) {
foo(List("String"))
foo(List(1, 2, 3))
}
}
The implicit manifest paramenter can be used to "reify" the erased type and thus hack around erasure. You can learn a bit more about it in many blog posts,e.g. this one.
What happens is that the manifest param can give you back what T was before erasure. Then a simple dispatch based on T to the various real implementation does the rest.
Probably there is a nicer way to do the pattern matching, but I haven't seen it yet. What people usually do is matching on m.toString, but I think keeping classes is a bit cleaner (even if it's a bit more verbose). Unfortunately the documentation of Manifest is not too detailed, maybe it also has something that could simplify it.
A big disadvantage of it is that it's not really type safe: foo will be happy with any T, if you can't handle it you will have a problem. I guess it could be worked around with some constraints on T, but it would further complicate it.
And of course this whole stuff is also not too nice, I'm not sure if it worth doing it, especially if you are lazy ;-)
Instead of using manifests you could also use dispatchers objects implicitly imported in a similar manner. I blogged about this before manifests came up: http://michid.wordpress.com/code/implicit-double-dispatch-revisited/
This has the advantage of type safety: the overloaded method will only be callable for types which have dispatchers imported into the current scope.
Nice trick I've found from http://scala-programming-language.1934581.n4.nabble.com/disambiguation-of-double-definition-resulting-from-generic-type-erasure-td2327664.html
by Aaron Novstrup
Beating this dead horse some more...
It occurred to me that a cleaner hack is to use a unique dummy type
for each method with erased types in its signature:
object Baz {
private object dummy1 { implicit val dummy: dummy1.type = this }
private object dummy2 { implicit val dummy: dummy2.type = this }
def foo(xs: String*)(implicit e: dummy1.type) = 1
def foo(xs: Int*)(implicit e: dummy2.type) = 2
}
[...]
I tried improving on Aaron Novstrup’s and Leo’s answers to make one set of standard evidence objects importable and more terse.
final object ErasureEvidence {
class E1 private[ErasureEvidence]()
class E2 private[ErasureEvidence]()
implicit final val e1 = new E1
implicit final val e2 = new E2
}
import ErasureEvidence._
class Baz {
def foo(xs: String*)(implicit e:E1) = 1
def foo(xs: Int*)(implicit e:E2) = 2
}
But that will cause the compiler to complain that there are ambiguous choices for the implicit value when foo calls another method which requires an implicit parameter of the same type.
Thus I offer only the following which is more terse in some cases. And this improvement works with value classes (those that extend AnyVal).
final object ErasureEvidence {
class E1[T] private[ErasureEvidence]()
class E2[T] private[ErasureEvidence]()
implicit def e1[T] = new E1[T]
implicit def e2[T] = new E2[T]
}
import ErasureEvidence._
class Baz {
def foo(xs: String*)(implicit e:E1[Baz]) = 1
def foo(xs: Int*)(implicit e:E2[Baz]) = 2
}
If the containing type name is rather long, declare an inner trait to make it more terse.
class Supercalifragilisticexpialidocious[A,B,C,D,E,F,G,H,I,J,K,L,M] {
private trait E
def foo(xs: String*)(implicit e:E1[E]) = 1
def foo(xs: Int*)(implicit e:E2[E]) = 2
}
However, value classes do not allow inner traits, classes, nor objects. Thus also note Aaron Novstrup’s and Leo’s answers do not work with a value classes.
I didn't test this, but why wouldn't an upper bound work?
def foo[T <: String](s: List[T]) { println("Strings: " + s) }
def foo[T <: Int](i: List[T]) { println("Ints: " + i) }
Does the erasure translation to change from foo( List[Any] s ) twice, to foo( List[String] s ) and foo( List[Int] i ):
http://www.angelikalanger.com/GenericsFAQ/FAQSections/TechnicalDetails.html#FAQ108
I think I read that in version 2.8, the upper bounds are now encoded that way, instead of always an Any.
To overload on covariant types, use an invariant bound (is there such a syntax in Scala?...ah I think there isn't, but take the following as conceptual addendum to the main solution above):
def foo[T : String](s: List[T]) { println("Strings: " + s) }
def foo[T : String2](s: List[T]) { println("String2s: " + s) }
then I presume the implicit casting is eliminated in the erased version of the code.
UPDATE: The problem is that JVM erases more type information on method signatures than is "necessary". I provided a link. It erases type variables from type constructors, even the concrete bound of those type variables. There is a conceptual distinction, because there is no conceptual non-reified advantage to erasing the function's type bound, as it is known at compile-time and does not vary with any instance of the generic, and it is necessary for callers to not call the function with types that do not conform to the type bound, so how can the JVM enforce the type bound if it is erased? Well one link says the type bound is retained in metadata which compilers are supposed to access. And this explains why using type bounds doesn't enable overloading. It also means that JVM is a wide open security hole since type bounded methods can be called without type bounds (yikes!), so excuse me for assuming the JVM designers wouldn't do such an insecure thing.
At the time I wrote this, I didn't understand that stackoverflow was a system of rating people by quality of answers like some competition over reputation. I thought it was a place to share information. At the time I wrote this, I was comparing reified and non-reified from a conceptual level (comparing many different languages), and so in my mind it didn't make any sense to erase the type bound.