I was kind of disappointed by the fact that scala compiler allows to compile this pretty wierd, obviously mistaken code:
val foo: PartialFunction[Any, Unit] = {
case s: String => println(s)
}
foo()
and instead of printing compile-error, it throws
Exception in thread "main" scala.MatchError: () (of class scala.runtime.BoxedUnit)
What was the reason for that?
In your case your partial function takes an Any argument, and that includes Unit (since unit is a subtype of Any - Any -> AnyVal -> Unit). Calling apply() on that is equal to calling apply(()).
If you have a partial function which doesn't accept Unit you get an error indicating that the argument for apply is missing:
scala> val foo : PartialFunction[AnyRef, Unit] = {
| case arg => println(s"arg = $arg")
| }
foo: PartialFunction[AnyRef,Unit] = <function1>
scala> foo()
<console>:13: error: not enough arguments for method apply: (v1: AnyRef)Unit in trait Function1.
Unspecified value parameter v1.
foo()
What was the reason for that?
Because when accepting a parameter of type Any, the compiler deduces that type of Unit is applicable in that case, and thus passes the Unit type to foo.apply of the PartialFunction:
def main(args: Array[String]): Unit = {
val foo: PartialFunction[Any,Unit] = ({
#SerialVersionUID(value = 0) final <synthetic> class $anonfun extends scala.runtime.AbstractPartialFunction[Any,Unit] with Serializable {
def <init>(): <$anon: Any => Unit> = {
$anonfun.super.<init>();
()
};
final override def applyOrElse[A1, B1 >: Unit](x1: A1, default: A1 => B1): B1 = ((x1.asInstanceOf[Any]: Any): Any #unchecked) match {
case (s # (_: String)) => scala.this.Predef.println(s)
case (defaultCase$ # _) => default.apply(x1)
};
final def isDefinedAt(x1: Any): Boolean = ((x1.asInstanceOf[Any]: Any): Any #unchecked) match {
case (s # (_: String)) => true
case (defaultCase$ # _) => false
}
};
new $anonfun()
}: PartialFunction[Any,Unit]);
foo.apply(())
}
If the type restriction was narrower, i.e AnyRef, you'd see a compiler error as Unit inherits AnyVal, and now the compiler can't provide any implicit "help".
Related
Scala compiler detects the following two map functions as duplicates conflicting with each other:
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output): List[Output] = ???
}
The class type of Output parameter is different. First one limits to AnyVal and second one limits to AnyRef. How can I differentiate them?
The problem is not differentiating AnyVal from AnyRef so much as getting around the fact that both method signatures become the same after erasure.
Here is a neat trick to get around this kind of problem. It is similar to what #som-snytt did, but a bit more generic, as it works for other similar situations as well (e.g. def foo(f: Int => String): String = ??? ; def foo(f: String => Int): Int = ??? etc.):
class ADT {
def map[Output <: AnyVal](f: Int => Output): List[Output] = ???
def map[Output >: Null <: AnyRef](f: Int => Output)(implicit dummy: DummyImplicit): List[Output] = ???
}
The cutest thing is that this works "out of the box". Apparently, a DummyImplicit is a part of standard library, and you always have the thing in scope.
You can have more than two overloads this way too by just adding more dummies to the list.
scala 2.13.0-M5> :pa
// Entering paste mode (ctrl-D to finish)
object X {
def map[Output <: AnyVal](f: Int => Output) = 1
def map[O](f: Int => O)(implicit ev: O <:< AnyRef) = 2
}
// Exiting paste mode, now interpreting.
defined object X
scala 2.13.0-M5> X.map((x: Int) => x*2)
res0: Int = 1
scala 2.13.0-M5> X.map((x: Int) => "")
res1: Int = 2
You could use a typeclass for that map method.
Using your exact example:
trait MyTC[Output]{
def map(f: Int => Output): List[Output]
}
object MyTC{
def apply[A](a : A)(implicit ev : MyTC[A]) : MyTC[A] = ev
implicit def anyRefMyTc[A <: AnyRef] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyRef"); List.empty }
}
implicit def anyValMyTc[A <: AnyVal] : MyTC[A] = new MyTC[A]{
def map(f: Int => A): List[A] = { println("inside sub-AnyVal"); List.empty }
}
}
import MyTC._
val r1 = Option("Test1")
val r2 = List(5)
val v1 = true
val v2 = 6L
// The functions here are just to prove the point, and don't do anything.
MyTC(r1).map(_ => None)
MyTC(r2).map(_ => List.empty)
MyTC(v1).map(_ => false)
MyTC(v2).map(_ => 10L)
That would print:
inside sub-AnyRef
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal
The advantage of this approach is that, should you then choose to specialise the behaviour further for just some specific type (e.g. say you want to do something specific for Option[String]), you can do that easily:
// This is added to MyTC object
implicit val optMyTc : MyTC[Option[String]] = new MyTC[Option[String]]{
def map(f: Int => Option[String]): List[Option[String]] = { println("inside Option[String]"); List.empty }
}
Then, re-running the code will print:
inside Option[String]
inside sub-AnyRef
inside sub-AnyVal
inside sub-AnyVal
I've implemented a custom collection class which is basically a Map with implicit integer keys and values that are subclasses of AnyRef. It uses the Int keys as index for underlying array structure. Here is the class declaration signature (class instantiation is done in companion object, hence private constructor):
class ArrayMap[T >: Null <: AnyRef: ClassTag] private (private var data: Array[T]) { self =>
...
}
Now I want to add required methods for for-comprehension. I've defined two different map functions. One that returns a List and the other one returns the same data type (ArrayMap).
def map[X](f: (Int, T) => X): List[X] = { ... }
def map[X >: Null <: AnyRef: ClassTag](f: (Int, T) => X): ArrayMap[X] = { ... }
def foreach(f: (Int, T) => Unit): Unit = { ... }
def flatMap[X >: Null <: AnyRef: ClassTag](f: (Int, T) => Iterable[(Int, X)]): ArrayMap[X] = { ... }
def filter(p: (Int, T) => Boolean): ArrayMap[T] = { ... }
No implicit is defined. Above functions work as expected when used separately. The problem is in for-comprehensions. For loop either picks the first map which returns List or throws a mysterious error. The following example produces error:
val map = ArrayMap.empty[Integer]
map(0) = 0
map(1) = 1
map(5) = 2
map(6) = 3
map(10) = 4
val rs: ArrayMap[String] = for (e <- map) yield e._2.toString
Above code throws:
Error:(293, 41) missing parameter type
val rs: ArrayMap[String] = for (e <- map) yield e._2.toString
What am I missing?
[UPDATE]
The full implementation is available as a gist here.
The problem is related to a type mismatch, you defined the function to pass to map as a function of two arguments (Int & T) to X. while in your for comprehension you treat it as a function of one argument (a tuple (Int, T)) to X.
The simplest solution is to redefine your map function signature. e.g.
import scala.reflect.ClassTag
class ArrayMap[T >: Null <: AnyRef: ClassTag] (val data: Array[T]) {
// Note the double parenthesis (()).
def map[X >: Null <: AnyRef: ClassTag](f: ((Int, T)) => X): ArrayMap[X] = ???
def withFilter(p: ((Int, T)) => Boolean): ArrayMap[T] = ???
}
With that definition you can make something like
val map: ArrayMap[java.lang.Integer] = new ArrayMap(Array(1, 2, 3))
// Note I use lazy val to avoid the NotImplementedException.
lazy val rs1: ArrayMap[String] = map.map(tuple => tuple._2.toString)
lazy val rs2: ArrayMap[String] = map.map { case (_, v) => v.toString }
lazy val rs3: ArrayMap[String] = for {
tuple <- map
} yield tuple._2.toString
lazy val rs4: ArrayMap[String] = for {
(_, v) <- map
} yield v.toString
See the full signature of map in Scala Map as a reference.
Consider the following Scala code snippet:
def func(param: Any): Int = param match {
case f: (String => Int) => f("apple")
case i: Int => i
}
println(func((s: String) => s.length))
Works as expected, however, at compilation I get the following warning:
<console>:11: warning: non-variable type argument String in type pattern String => Int is unchecked since it is eliminated by erasure
case f: (String => Int) => f("apple")
How can I get rid of this warning message?
Thanks your help in advance!
The reason why you get the message is because of Java's generic type erasure. In this particular case, your function which is of type Function[String, Int] will be matched by any Function[A, B].
In order to get rid of this warning you should use scala typetags which will allow you to differentiate between the different function types.
The code snippet is below,
import scala.reflect.runtime.universe._
object Answer {
def function[A](param: A)(implicit tt: TypeTag[A]): String = param match {
case f: (String => Int) #unchecked if typeOf[String => Int] =:= typeOf[A] => f("apple").toString
case f: (Int => String) #unchecked if typeOf[Int => String] =:= typeOf[A] => f(32 + 1)
case s: String => s"hello $s"
}
def main (args: Array[String]) {
println(function((s: String) => s.length))
println(function((i: Int) => i.toString))
println(function("world"))
}
}
The key part is to have an implicit TypeTag[A] which is added at compile time which includes the metadata that the function typeOf needs to check the types of A against anything else.
Essentially, what I would like to do is write overloaded versions of "map" for a custom class such that each version of map differs only by the type of function passed to it.
This is what I would like to do:
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
Of course, because of type erasure, this won't work. Either version of map will work alone, and they can be named differently and everything works fine. However, it is very important that a user can call the correct map function simply based on the type of the function passed to it.
In my search for how to solve this problem, I cam across TypeTags. Here is the code I came up with that I believe is close to correct, but of course doesn't quite work:
import scala.reflect.runtime.universe._
object Test {
case class Foo(name: String, value: Int)
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map[A: TypeTag](func: A => A) =
typeOf[A] match {
case i if i =:= typeOf[Int => Int] => f.mapI(func)
case s if s =:= typeOf[String => String] => f.mapS(func)
}
def mapI(func: Int => Int) = Foo(f.name, func(f.value))
def mapS(func: String => String) = Foo(func(f.name), f.value)
}
def main(args: Array[String])
{
def square(n: Int): Int = n * n
def rev(s: String): String = s.reverse
val f = Foo("Test", 3)
println(f.string)
val g = f.map(rev)
val h = g.map(square)
println(h.string)
}
}
When I attempt to run this code I get the following errors:
[error] /src/main/scala/Test.scala:10: type mismatch;
[error] found : A => A
[error] required: Int => Int
[error] case i if i =:= typeOf[Int => Int] => f.mapI(func)
[error] ^
[error] /src/main/scala/Test.scala:11: type mismatch;
[error] found : A => A
[error] required: String => String
[error] case s if s =:= typeOf[String => String] => f.mapS(func)
It is true that func is of type A => A, so how can I tell the compiler that I'm matching on the correct type at runtime?
Thank you very much.
In your definition of map, type A means the argument and result of the function. The type of func is then A => A. Then you basically check that, for example typeOf[A] =:= typeOf[Int => Int]. That means func would be (Int => Int) => (Int => Int), which is wrong.
One of ways of fixing this using TypeTags looks like this:
def map[T, F : TypeTag](func: F)(implicit ev: F <:< (T => T)) = {
func match {
case func0: (Int => Int) #unchecked if typeOf[F] <:< typeOf[Int => Int] => f.mapI(func0)
case func0: (String => String) #unchecked if typeOf[F] <:< typeOf[String => String] => f.mapS(func0)
}
}
You'd have to call it with an underscore though: f.map(rev _). And it may throw match errors.
It may be possible to improve this code, but I'd advise to do something better. The simplest way to overcome type erasure on overloaded method arguments is to use DummyImplicit. Just add one or several implicit DummyImplicit arguments to some of the methods:
implicit class FooUtils(f: Foo) {
def string() = s"${f.name}: ${f.value}"
def map(func: Int => Int)(implicit dummy: DummyImplicit) = Foo(f.name, func(f.value))
def map(func: String => String) = Foo(func(f.name), f.value)
}
A more general way to overcome type erasure on method arguments is to use the magnet pattern. Here is a working example of it:
sealed trait MapperMagnet {
def map(foo: Foo): Foo
}
object MapperMagnet {
implicit def forValue(func: Int => Int): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(foo.name, func(foo.value))
}
implicit def forName(func: String => String): MapperMagnet = new MapperMagnet {
override def map(foo: Foo): Foo = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
// Might be simply `def map(func: MapperMagnet) = func.map(f)`
// but then it would require those pesky underscores `f.map(rev _)`
def map[T](func: T => T)(implicit magnet: (T => T) => MapperMagnet): Foo =
magnet(func).map(f)
}
This works because when you call map, the implicit magnet is resolved at compile time using full type information, so no erasure happens and no runtime type checks are needed.
I think the magnet version is cleaner, and as a bonus it doesn't use any runtime reflective calls, you can call map without underscore in the argument: f.map(rev), and also it can't throw runtime match errors.
Update:
Now that I think of it, here magnet isn't really simpler than a full typeclass, but it may show the intention a bit better. It's a less known pattern than typeclass though. Anyway, here is the same example using the typeclass pattern for completeness:
sealed trait FooMapper[F] {
def map(foo: Foo, func: F): Foo
}
object FooMapper {
implicit object ValueMapper extends FooMapper[Int => Int] {
def map(foo: Foo, func: Int => Int) = Foo(foo.name, func(foo.value))
}
implicit object NameMapper extends FooMapper[String => String] {
def map(foo: Foo, func: String => String) = Foo(func(foo.name), foo.value)
}
}
implicit class FooUtils(f: Foo) {
def string = s"${f.name}: ${f.value}"
def map[T](func: T => T)(implicit mapper: FooMapper[T => T]): Foo =
mapper.map(f, func)
}
I want to be able to define a method with the same name that has a different implementation if the argument is an Iterable[T1] vs a function: T1 => T2
However, many classes that implement Iterable also implement PartialFunction
For example:
object FunList {
def foo(itr: Iterable[Int]) = println("hello")
def foo(f: (Int => Int)) = println("Goodbye")
}
scala> FunList.foo(List(1))
<console>:9: error: ambiguous reference to overloaded definition,
both method foo in object FunList of type (f: Int => Int)Unit
and method foo in object FunList of type (itr: Iterable[Int])Unit
match argument types (List[Int])
FunList.foo(List(1))
currently my solution looks like this, but it does not match subclasses of Iterable which are not also subclasses of PartialFunction
case class SeqOrFun[T1, T2](f: (T1 => T2))
implicit def seqOrFun[T1, T2](f: (T1 => T2)) = SeqOrFun(f)
def unfurl[T1: Numeric, T2: Numeric](x: SeqOrFun[T1, T2], y: SeqOrFun[T1, T2]) = {
(x.f, y.f) match {
case (xs: Iterable[T1], ys: Iterable[T2]) => (xs, ys)
case (xf: (T2 => T1), ys: Iterable[T2]) => (ys.map(xf), ys)
case (xs: Iterable[T1], yf: (T1 => T2)) => (xs, xs.map(yf))
}
}
Since List is both Iterable[Int] and Int => Int, as you've said, what you're writing is inherently abmiguous. Perhaps I've misread, but I don't see any place at all where you've specified whether you want FunList.foo(List(1)) to print "hello" or "Goodbye".
First, you can use a cast at the call site. I assume you already know this, but just to be explicit for the sake of discussion:
FunList.foo(List(1): Int => Int) // "hello"
FunList.foo(List(1): Iterable[Int]) // "Goodbye"
If our objective here is to allow the caller to simply write FunList.foo(List(1)), you could use the magnet pattern. This means you don't use method overloading at all; instead you write a single method, and the dispatch is done with implicit conversions.
sealed trait FooMagnet
case class HelloMagnet(itr: Iterable[Int]) extends FooMagnet
case class GoodbyeMagnet(f: Int => Int) extends FooMagnet
def foo(x: FooMagnet): Unit = x match {
case HelloMagnet(itr) => println("hello")
case GoodbyeMagnet(f) => println("Goodbye")
}
def a(): Unit = {
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
FunList.foo(List(1)) // "hello"
}
def b(): Unit = {
implicit def listIsGoodbyeMagnet(x: List[Int]): FooMagnet = GoodbyeMagnet(x)
FunList.foo(List(1)) // "Goodbye"
}
The fun advantage you get here is that the dispatch decision is decoupled from the foo implementation, since it's determined by those implicits which you can define wherever you like.
You can also use this to resolve the ambiguity problem! Start with the two implicits from earlier:
implicit def iterableIsHelloMagnet(x: Iterable[Int]): FooMagnet = HelloMagnet(x)
implicit def functionIsGoodbyeMagnet(x: Int => Int): FooMagnet = GoodbyeMagnet(x)
And then add another implicit specifically for List[Int].
implicit def listIsHelloMagnet(x: List[Int]): FooMagnet = HelloMagnet(x)
Scala is clever enough to see that this third conversion is more specific than the first two, so it will use that one for List[Int] even though they all apply. Thus we can now write:
FunList.foo(Set(1)) // "hello"
FunList.foo((_: Int) + 1) // "Goodbye"
FunList.foo(List(1)) // "hello"
And you can move the definitions of those implicits into the called library, so all the caller has to do is import them.