Removing ambiguity of overloaded method definition - scala

The compiler is getting confused by an overloaded method definiton and I cannot find a way to clarify my intention sufficiently.
I have the following code:
val part: (QueryParams) => List[ResultMap] = (partOf.find _).andThen(makeMap)
The find method is overloaded:
def find(params: QueryParams): List[U] = ...
def find(params: QueryParams, flattener: U => T): List[T] = ...
The code was working fine as long as there was a single definiton of find. Since I had to add the second find definiton with 2 params, the compiler is generating this error:
Error:(15, 31) ambiguous reference to overloaded definition,
both method find in trait DataFetcher of type (params: ...QueryParams)List[...Parser]
and method find in trait DataFetcher of type (params: ...QueryParams, flattener: ...Parser => ...ResultTuple)List[...ResultTuple]
match expected type ?
val part: Fetcher = (partOf.find _).andThen(makeMap)
^
IMHO there is no ambiguity. The type of part is defined to accept one argument of type QueryParams. There is only one method accepting a single QueryParams. U and T are different types and makeMap expects a List[U] There are no implicits, default values or varargs involved.
Is there a way to further clarify my intention to the compiler?
EDIT: one way to remove the ambiguity is to introduce an intermediary value, clarifying the expected type of the eta expansion:
val find: (QueryParams) => List[ResultTuple] = partOf.find _
val part: (QueryParams) => List[ResultMap] = find andThen makeMap
But since makeMap is only accepting List[ResultTuple] I stil dont get the reason for the supposed ambiguity and would prefer not to introduce the extra value. Any clarification?

First, it is important to understand that the trailing underscore is a deliberate design decision to prevent programmer mistakes. The only exception is when the type is explicitly declared.
Here is an example illustrating this point.
object A {
def add(a: Int)(b:Int): Int = a + b
val x: Int => Int = add(5) // compiles fine
val y = add(5) // produces a compiler error
}
The same applies to your question. Because you do not specify the intermediate type, when you write find _, should the compiler infer the type to be QueryParams => List[ResultTuple] (as you may expect) or should it be (QueryParams, U => T) => List[ResultTuple]? Note that the trailing underscore does not stand for a single argument, it just lifts the method to a function. When the type if declared, you can drop the trailing underscore and write find where you would have written find _.
I see from your edit that you found out that an intermediate value with a declared type works. Another (slightly clunky) way to clarify your intent is the following.
val part: (QueryParams) => List[ResultMap] = (x => partOf.find(x)).andThen(makeMap)

Related

Mysterious GADT skolem: What type is trying to escape its scope?

Scala 11.2 is giving me this error:
error: type mismatch;
found : Seq[Some[V]]
required: Seq[Option[?V8]] where type ?V8 <: V (this is a GADT skolem)
val output = f(ivs.map(iv => Some(iv.get._1)))
^
First off, this seems like a strange error message: Doesn't Seq[Some[V]] conform to Seq[Option[V]]?
Here are the parts of the surrounding code that seem relevant:
def evalDependencyTree[V]
(linkRelevance: LinkInfo => Option[LinkStrength])
(dtree: DependencyTree[V, LinkInfo], strengthSoFar: LinkStrength = 1.0)
: Option[(V, LinkStrength)] = dtree match {
. . .
case DFunction(f, inputs) => {
val ivs = inputs.map { input =>
evalDependencyTree(linkRelevance)(input, strengthSoFar) // <-- Recursive call
}
val output = f(ivs.map(iv => Some(iv.get._1))) // <-- The line with the error
. . .
}
}
trait DependencyTree[+V, +L]
case class DFunction[V, L](
f: Seq[Option[V]] => Option[V], inputs: Seq[DependencyTree[V, L]])
extends DependencyTree[V, L]
My (very limited) understanding of GADT skolems is that they're types defined by the compiler during type inference, which copy an existing type argument in order to prevent that type from "escaping" its scope, as in a recursive call—that is, to prevent its being referred to from a wider scope that has no access to the type.
I don't see how V could refer to different types in different scopes here. The recursive call to evalDependencyTree has the same type argument, V, as the current call to evalDependencyTree. I tried explicitly writing evalDependencyTree[V] for the recursive call, but the compiler returned the same error message. This code did work when evalDependencyTree did not have a type argument; in that version, dtree was hard-coded to DependencyTree[Int, LinkInfo].
What type is trying to escape? Or rather, what am I doing wrong?
I found a workaround myself: explicitly spell out the full type of f in the pattern-match, like this:
case DFunction(f: Seq[Option[V]] => Option[V], inputs) => . . .
This works, but I'm not accepting it as an answer because I don't have an explanation of why it's necessary. I still don't know when to expect this kind of error or what causes it. If you know, please post an answer!
Also, I would have thought that most of the type explicitly provided for f would have been lost by type erasure. So, there are two important things I can't explain about this workaround.

Demystifying a function definition

I am new to Scala, and I hope this question is not too basic. I couldn't find the answer to this question on the web (which might be because I don't know the relevant keywords).
I am trying to understand the following definition:
def functionName[T <: AnyRef](name: Symbol)(range: String*)(f: T => String)(implicit tag: ClassTag[T]): DiscreteAttribute[T] = {
val r = ....
new anotherFunctionName[T](name.toString, f, Some(r))
}
First , why is it defined as def functionName[...](...)(...)(...)(...)? Can't we define it as def functionName[...](..., ..., ..., ...)?
Second, how does range: String* from range: String?
Third, would it be a problem if implicit tag: ClassTag[T] did not exist?
First , why is it defined as def functionName...(...)(...)(...)? Can't we define it as def functionName[...](..., ..., ..., ...)?
One good reason to use currying is to support type inference. Consider these two functions:
def pred1[A](x: A, f: A => Boolean): Boolean = f(x)
def pred2[A](x: A)(f: A => Boolean): Boolean = f(x)
Since type information flows from left to right if you try to call pred1 like this:
pred1(1, x => x > 0)
type of the x => x > 0 cannot be determined yet and you'll get an error:
<console>:22: error: missing parameter type
pred1(1, x => x > 0)
^
To make it work you have to specify argument type of the anonymous function:
pred1(1, (x: Int) => x > 0)
pred2 from the other hand can be used without specifying argument type:
pred2(1)(x => x > 0)
or simply:
pred2(1)(_ > 0)
Second, how does range: String* from range: String?
It is a syntax for defining Repeated Parameters a.k.a varargs. Ignoring other differences it can be used only on the last position and is available as a scala.Seq (here scala.Seq[String]). Typical usage is apply method of the collections types which allows for syntax like SomeDummyCollection(1, 2, 3). For more see:
What does `:_*` (colon underscore star) do in Scala?
Scala variadic functions and Seq
Is there a difference in Scala between Seq[T] and T*?
Third, would it be a problem if implicit tag: ClassTag[T] did not exist?
As already stated by Aivean it shouldn't be the case here. ClassTags are automatically generated by the compiler and should be accessible as long as the class exists. In general case if implicit argument cannot be accessed you'll get an error:
scala> import scala.concurrent._
import scala.concurrent._
scala> val answer: Future[Int] = Future(42)
<console>:13: error: Cannot find an implicit ExecutionContext. You might pass
an (implicit ec: ExecutionContext) parameter to your method
or import scala.concurrent.ExecutionContext.Implicits.global.
val answer: Future[Int] = Future(42)
Multiple argument lists: this is called "currying", and enables you to call a function with only some of the arguments, yielding a function that takes the rest of the arguments and produces the result type (partial function application). Here is a link to Scala documentation that gives an example of using this. Further, any implicit arguments to a function must be specified together in one argument list, coming after any other argument lists. While defining functions this way is not necessary (apart from any implicit arguments), this style of function definition can sometimes make it clearer how the function is expected to be used, and/or make the syntax for partial application look more natural (f(x) rather than f(x, _)).
Arguments with an asterisk: "varargs". This syntax denotes that rather than a single argument being expected, a variable number of arguments can be passed in, which will be handled as (in this case) a Seq[String]. It is the equivalent of specifying (String... range) in Java.
the implicit ClassTag: this is often needed to ensure proper typing of the function result, where the type (T here) cannot be determined at compile time. Since Scala runs on the JVM, which does not retain type information beyond compile time, this is a work-around used in Scala to ensure information about the type(s) involved is still available at runtime.
Check currying:Methods may define multiple parameter lists. When a method is called with a fewer number of parameter lists, then this will yield a function taking the missing parameter lists as its arguments.
range:String* is the syntax for varargs
implicit TypeTag parameter in Scala is the alternative for Class<T> clazzparameter in Java. It will be always available if your class is defined in scope. Read more about type tags.

Why does Scala require partial application of curried functions when assigning to a val?

In Scala, why is it that a curried function can easily be passed directly to other functions, but when assigning it to a val one needs to also partially apply it with _? For example, given the two functions:
def curried(a: Int)(b: Int) = a + b
def test(a: Int, f: Int => Int) = f(a)
I can easily pass curried to test with:
test(5, curried(5))
and everything is happy. However if I simply call curried(5) I get an error:
scala> curried(5)
<console>:9: error: missing arguments for method curried;
follow this method with `_' if you want to treat it as a partially applied function
curried(5)
If I change the call to include type information however, it works:
val 'curried: Int => Int = curried(5)
Can anyone explain the rational behind the inconsistency, surely the Scala compiler can infer that the function is Int => Int given the type definition on the original method?
The problem is not inferring the type, the problem is inferring your intent. Did you make a mistake, or did you intentionally curry the function?
Alas, the trailing underscore syntax is the formal syntax, and omitting it is syntactical sugar.
The underscore isn't always needed. From http://docs.scala-lang.org/cheatsheets/
val zscore = (mean:R, sd:R) => (x:R) => (x-mean)/sd
currying, obvious syntax.
def zscore(mean:R, sd:R) = (x:R) => (x-mean)/sd
currying, obvious syntax
def zscore(mean:R, sd:R)(x:R) = (x-mean)/sd
currying, sugar syntax. but then:
val normer = zscore(7, 0.4) _
need trailing underscore to get the partial, only for the sugar version.

redundant parameter type info in partially applied function definition

def foo(num:Int, str:String):Int = 1
val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => test(3, x$1))"
val baz = foo(3, _:String) // compiles fine
Why do I have to explicitly specify the type of _ when it looks inferrable from the context?
EDIT: Renamed to avoid name collision following David Soergel's suggest.
First of all, to avoid confusion between "def test" and "val test", let's write:
def foo(num:Int, str:String):Int = 1
val bar = foo(3, _) // compiler complains "missing parameter type for expanded function ((x$1) => foo(3, x$1))"
val baz = foo(3, _:String) // compiles fine
What's inferrable from context is only that the argument to bar must somehow be convertible to a String. That could be due to inheritance (if instead of String you use some non-final type there), or due to an implicit conversion.
Basically the potential for implicits means that the argument to bar could be just about any type at all, so the code as written is indeed underspecified. I don't know whether the compiler actually checks whether there are any appropriate implicit conversions in scope before issuing the "missing type" error, but I would guess not. (In the case of String there are likely to be a bunch present, anyway). It would be brittle and confusing if the signature of baz changed as a result of importing a new implicit that could produce a String.
I think David Soergel's explanation is essentially correct: if type T has an implicit conversion to String then val bar = foo(3, _:T) is valid, giving a function of type T => Int, which is unrelated to String => Int.
Why the compiler doesn't make a sensible assumption (in the absence of explicit typing) that the type is in fact the same as in the method (which is the essence of your question), I don't know - I can only guess it's because it would complicate the language spec.
Where no types are specified, i.e. val bar = foo(_, _), it seems the compiler interprets it as simple eta-conversion, the same as val bar = foo _, which does give a String => Int.
My preferred idiom would be to give the function type on the left hand side, which has the benefit of allowing you to easily see bar's type:
val bar: String => Int = foo(3, _)
If you're allergic to re-typing the word String, you could write
val bar = (foo _).curried(3)

Spurious ambiguous reference error in Scala 2.7.7 compiler/interpreter?

Can anyone explain the compile error below? Interestingly, if I change the return type of the get() method to String, the code compiles just fine. Note that the thenReturn method has two overloads: a unary method and a varargs method that takes at least one argument. It seems to me that if the invocation is ambiguous here, then it would always be ambiguous.
More importantly, is there any way to resolve the ambiguity?
import org.scalatest.mock.MockitoSugar
import org.mockito.Mockito._
trait Thing {
def get(): java.lang.Object
}
new MockitoSugar {
val t = mock[Thing]
when(t.get()).thenReturn("a")
}
error: ambiguous reference to overloaded definition,
both method thenReturn in trait OngoingStubbing of type
java.lang.Object,java.lang.Object*)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
and method thenReturn in trait OngoingStubbing of type
(java.lang.Object)org.mockito.stubbing.OngoingStubbing[java.lang.Object]
match argument types (java.lang.String)
when(t.get()).thenReturn("a")
Well, it is ambiguous. I suppose Java semantics allow for it, and it might merit a ticket asking for Java semantics to be applied in Scala.
The source of the ambiguitity is this: a vararg parameter may receive any number of arguments, including 0. So, when you write thenReturn("a"), do you mean to call the thenReturn which receives a single argument, or do you mean to call the thenReturn that receives one object plus a vararg, passing 0 arguments to the vararg?
Now, what this kind of thing happens, Scala tries to find which method is "more specific". Anyone interested in the details should look up that in Scala's specification, but here is the explanation of what happens in this particular case:
object t {
def f(x: AnyRef) = 1 // A
def f(x: AnyRef, xs: AnyRef*) = 2 // B
}
if you call f("foo"), both A and B
are applicable. Which one is more
specific?
it is possible to call B with parameters of type (AnyRef), so A is
as specific as B.
it is possible to call A with parameters of type (AnyRef,
Seq[AnyRef]) thanks to tuple
conversion, Tuple2[AnyRef,
Seq[AnyRef]] conforms to AnyRef. So
B is as specific as A. Since both are
as specific as the other, the
reference to f is ambiguous.
As to the "tuple conversion" thing, it is one of the most obscure syntactic sugars of Scala. If you make a call f(a, b), where a and b have types A and B, and there is no f accepting (A, B) but there is an f which accepts (Tuple2(A, B)), then the parameters (a, b) will be converted into a tuple.
For example:
scala> def f(t: Tuple2[Int, Int]) = t._1 + t._2
f: (t: (Int, Int))Int
scala> f(1,2)
res0: Int = 3
Now, there is no tuple conversion going on when thenReturn("a") is called. That is not the problem. The problem is that, given that tuple conversion is possible, neither version of thenReturn is more specific, because any parameter passed to one could be passed to the other as well.
In the specific case of Mockito, it's possible to use the alternate API methods designed for use with void methods:
doReturn("a").when(t).get()
Clunky, but it'll have to do, as Martin et al don't seem likely to compromise Scala in order to support Java's varargs.
Well, I figured out how to resolve the ambiguity (seems kind of obvious in retrospect):
when(t.get()).thenReturn("a", Array[Object](): _*)
As Andreas noted, if the ambiguous method requires a null reference rather than an empty array, you can use something like
v.overloadedMethod(arg0, null.asInstanceOf[Array[Object]]: _*)
to resolve the ambiguity.
If you look at the standard library APIs you'll see this issue handled like this:
def meth(t1: Thing): OtherThing = { ... }
def meth(t1: Thing, t2: Thing, ts: Thing*): OtherThing = { ... }
By doing this, no call (with at least one Thing parameter) is ambiguous without extra fluff like Array[Thing](): _*.
I had a similar problem using Oval (oval.sf.net) trying to call it's validate()-method.
Oval defines 2 validate() methods:
public List<ConstraintViolation> validate(final Object validatedObject)
public List<ConstraintViolation> validate(final Object validatedObject, final String... profiles)
Trying this from Scala:
validator.validate(value)
produces the following compiler-error:
both method validate in class Validator of type (x$1: Any,x$2: <repeated...>[java.lang.String])java.util.List[net.sf.oval.ConstraintViolation]
and method validate in class Validator of type (x$1: Any)java.util.List[net.sf.oval.ConstraintViolation]
match argument types (T)
var violations = validator.validate(entity);
Oval needs the varargs-parameter to be null, not an empty-array, so I finally got it to work with this:
validator.validate(value, null.asInstanceOf[Array[String]]: _*)