Reputation: 523
Why do right-associative operators have issues with generic-typed functions, even though equivalent left-associative operators work just fine.
implicit class FunctionWrapper[T1, T2](func: T1 => T2) {
def >>>[T3](funcAfter: T2 => T3): T1 => T3 = {
func andThen funcAfter
}
def >>:[T0](funcBefore: T0 => T1): T0 => T2 = {
funcBefore andThen func
}
}
Following are the functions to be chained:
def intToFloat = Int.int2float _
def floatToString = (_: Float).toString
def identityF[T] = identity(_: T)
As expected, both operators work well with concrete-typed functions:
scala> (intToFloat >>> floatToString)(11)
res5: String = 11.0
scala> (intToFloat >>: floatToString)(11)
res6: String = 11.0
However, the >>: fails with generic-typed functions for some reason:
scala> (intToFloat >>> identityF >>> floatToString)(11)
res7: String = 11.0
scala> (intToFloat >>: identityF >>: floatToString)(11)
<console>:16: error: type mismatch;
found : Nothing => Nothing
required: T0 => Float
(intToFloat >>: identityF >>: floatToString)(11)
^
There are workarounds for this, one being
(intToFloat >>: (identityF (_: Float)) >>: floatToString)(11)
but it seems easy to infer the type of identityF in the given context, why does it fail?
Upvotes: 2
Views: 50
Reputation: 170839
When you have a right-associative operator, remember it's really
floatToString.>>:(identityF).>>:(intToFloat)
Since there is no type parameter given for identityF
, it's governed by local type inference rules. In this case it tries to find identityF
's type parameter first (I think, but the other way around runs into trouble as well); because >>:
's type parameter is still unknown, it doesn't know the argument type of the function. It gives up by inferring Nothing
and then fails to find a suitable type parameter for >>:
.
With andThen
or >>>
, Scala knows expected argument type for identityF
already and so can infer the correct type parameter.
That is, the problem isn't that >>:
is right-associative, it's the asymmetry between argument and return types. If you define >>:[T0](f: T1 => T0)
it'll work fine.
Upvotes: 2