Reputation: 2943
I can't quite understand why implicit conversions from Scala to JS values don't work this way:
import scala.scalajs.js
import scala.scalajs.js.JSConverters._
trait X extends js.Object {
def map(f: js.Function1[Int, String]) = js.native
def mapScala(f: Function1[Int, String]) = js.native // just for demo purpose, this is not really part of type X
def create(maybe: js.UndefOr[Int]) = js.native
}
def test(x: X) {
// I want these two lines to compile, but they don't
x.map(a => "yo") // error: missing parameter type
x.create(None) // error: type mismatch. Found None.type, required: js.UndefOr[Int]
// This works, but is too verbose
x.map((a: Int) => "yo") // only if arg type specified like this
x.mapScala(a => "yo") // because mapScala expects a Scala Function1
x.create(JSRichOption(None).orUndefined) // because value is manually converted
}
Am I trying to use implicit conversions the wrong way? The implementation of class X
is provided externally, in Javascript. In my code I want to pass native Scala values to methods of X
, I don't want to do the conversion manually each time.
I know there's an alternative way for Scala.js – to pimp my type X
like this, but I'm trying to avoid that because it's more boilerplate and a lot more objects will be instantiated at runtime that way. Regardless of that, I still do want to understand why exactly my code isn't working.
Upvotes: 2
Views: 221
Reputation: 14842
The reason the map
call does not work is a limitation in Scala's type inferencer: It needs to resolve the full type before looking for implicit conversions. However, Scala 2.12 brings SAM treatement just like Java. Roughly that means that you can write a lambda in stead of an anonymous class implementing an interface with a single method.
So x.map(a => "yo")
will expand into:
// Never (!) write this yourself.
x.map(new js.Function1[Int, String] {
def apply(a: Int): String = "yo"
})
Which the Scala.js compiler handles separately. You can enable SAM treatment in Scala 2.11 with the -Xexperimental
flag.
The reason the create
call does not work is that there is no implicit conversion (in the Scala.js standard library) from Option[T]
to js.UndefOr[T]
. There is an implicit conversion to JSRichOption[T]
which enables the orUndefined
method. You should write:
x.create(None.orUndefined)
Or in this case, you can simply write:
x.create(js.undefined)
Upvotes: 2