Tested with 2.13, but I presume it's been like that since 2.12 and I just had not encountered this type of problem before:
trait Extractor[-X, +Y] {
def optional :X => Option[Y] = apply
def apply(x :X) :Option[Y]
def andThen[Z](extractor :Extractor[Y, Z]) :Extractor[X, Z] = {
val first = optional; val second = extractor.optional
Extractor { x :X => first(x).flatMap(second) }
}
def andThen[Z](req :Y => Z) :Extractor[X, Z] = {
val first = optional
Extractor { x :X => first(x).map(req) }
}
def compose[W](extractor :Extractor[W, X]) :Extractor[W, Y] = extractor andThen this
def compose[W](req :W => X) :Extractor[W, Y] = Extractor(req andThen optional)
}
Scalac has a cryptic complaint about the implementation of the first compose
:
Error:(44, 31) type mismatch;
found : net.noresttherein.oldsql.morsels.Extractor[X,Y]
required: W => ?
def compose[W](extractor :Extractor[W, X]) :Extractor[W, Y] = extractor andThen this
Commenting out the andThen
variant taking a function solves the issue.
So does changing the code to extractor.andThen[Y](this)
(explicit type parameter is the key here).
My guess is that somehow my SAM type gets promoted to a function, but I can't guess why would it take precedence over a method. As I provided here two 'solutions', I am looking not as much for workarounds, but to understand what is happening. It's the first time in years I don't understand what's happening and would like to eliminate similar issues in the future.
Possibly, you are falling afoul of the new rules for overloading resolution, which are designed to assist type inference.
The question is what is the "expected type" of the arg in extractor.andThen(this)
.
"The intuition for higher-order function parameter type inference is that all arguments must be of a function-like type."
So removing the apply
method breaks that condition and lets typing proceed.
The spec adds: "The intent is not to steer overloading resolution."
It should read: "The intent is not to break overloading resolution."
I guess good intentions pave many roads.
Edit: it works in 2.12 without the amended rules. Under the old system, there is no expected type if the method is overloaded.
Worth adding that it probably qualifies as a regression. For example, they could do a fallback typecheck under the previous rules.
Here is a ticket for it.