Reputation: 3088
Since Java 8 I can pass intead of
xyz.foreach(e -> System.out.println(e));
I can do the following
xyz.foreach(System.out::println)
I have seen this thread about how method references work, but the problem is the following:
Error:(16, 63) ambiguous reference to overloaded definition,
both method toJson in object IanesJsonHelper of type (source: IanesServer)String
and method toJson in object IanesJsonHelper of type (success: Boolean)String
match expected type Function[?,String]
val json = IanesJsonHelper.toJson(array,IanesJsonHelper.toJson _) ^
I do have 3 functions with the name "toJSON"
def toJson(id: Int): String
and
def toJson(success: Boolean): String
and
def toJson(source: IanesServer): String
The last one is the right one.
The function I was calling in the error message above is:
def toJson[T](source: Array[T], toJson: Function[T, String]): String
This is the relevant code:
val array = new Array[IanesServer](1)
array(0) = new IanesServer(1, "http://localhost:4567/", "Test")
val json = IanesJsonHelper.toJson(array,IanesJsonHelper.toJson)
I do not get what my mistake is:
Can someone please be aso kind as to point out the mistake? At the moment I strongly disagree, that the function is [?,String]. Any ideas?
Answer: Thanks for the quick answer, here is what I chose:
IanesJsonHelper.toJson[IanesServer](array,IanesJsonHelper.toJson)
Upvotes: 4
Views: 424
Reputation: 68710
def toJson[T](source: Array[T], toJson: Function[T, String]): String
You expected the compiler to infer toJson
to be of type Function[IanesServer, String]
because source
is of type Array[IanerServer]
- and therefore T
equals IanesServer
.
Unfortunately, the scala compiler is not that smart. There are two ways you can help the compiler here:
State the types explicitly
IanesJsonHelper.toJson[IanesServer](array, IanesJsonHelper.toJson _)
Split the parameters into two parameter lists:
def toJson[T](source: Array[T])(toJson: Function[T, String]): String
IanesJsonHelper.toJson(array)(IanesJsonHelper.toJson)
When you have two parameter lists, the arguments passed to the first list will tell the compiler how to bind T
, and the compiler will use those bindings for the remaining lists.
Here's another shorter example:
// doesn't compile - the compiler doesn't realize `_` is an Int and therefore doesn't know about the `+` operator
def map[A, B](xs: List[A], f: A => B) = ???
map(List(1,2,3), _ + 1)
//compiles fine
def map[A, B](xs: List[A])(f: A => B) = ???
map(List(1,2,3))(_ + 1)
This behavior may seem unfortunate, but there's a reason for it.
Scala, unlike Java or C#, uses all arguments in a function's parameter list to calculate their LUB (least upper bound) and use that to infer the function's generic type parameters.
For example:
scala> def f[A](x: A, y: A): A = x
f: [A](x: A, y: A)A
scala> f(Some(1), None)
res0: Option[Int] = Some(1)
Here, scala used both arguments (of types Some[Int]
and None
) to infer the type of A
(Option[Int]
- the LUB). And this is why scala needs you to tell it which overload of toJson
you're referring to.
C#, on the other hand, wouldn't allow this.
Compilation error (line 17, col 3): The type arguments for method 'Program.F(T, T)' cannot be inferred from the usage. Try specifying the type arguments explicitly.
One last note: LUBing is awesome but also presents its disadvantages.
Upvotes: 5