Removing ambiguity of overloaded method definition

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?

Answers


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)

Need Your Help

How to "interrupt" a while loop in C# and return to the same place (without using any Threading)

c# cosmos

I need help switching between while loops and resuming to the exact state that they were in.

Android Webview function calls not always working

android webview

I want to be able to zoom by webview to a given zoomfactor, and scroll to a specific coordinate.