user34812
user34812

Reputation: 523

Why does Scala type inferencing fail here

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

Answers (1)

Alexey Romanov
Alexey Romanov

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

Related Questions