1

I have the following code

def sendMoney[T <: MoneyType](fn: T => Future[T], input: T): Unit

which is called this way

case x: Any => (sendMoney(_, _).tupled(x match {
  case c: HoldsMoney => (createHold(_: HoldsMoney), c: HoldsMoney)
  case r: ReserveMoney => (createReserve(_: ReserveMoney), r: ReserveMoney)
})

HoldsMoney and ReserveMoney have the base type of MoneyType.

Scala compiler is throwing the following error.

missing parameter type for expanded function

Note, this works if

x match {
  case c: HoldsMoney => sendMoney(createHold(_: HoldsMoney), c)
  case r: ReserveMoney => sendMoney(createReserve(_: ReserveMoney), r)
}
ffff
  • 2,853
  • 1
  • 25
  • 44

2 Answers2

3

Consider the type of

x match {
  case c: HoldsMoney => (createHold(_: HoldsMoney), c: HoldsMoney)
  case r: ReserveMoney => (createReserve(_: ReserveMoney), r: ReserveMoney)
}

The type of createHold(_: HoldsMoney) is HoldsMoney => Future[HoldsMoney] and the type of createReserve(_: ReserveMoney) is ReserveMoney => Future[ReserveMoney].

Because functions are contravariant in their argument type, the common type of those two functions can only be Nothing => Future[MoneyType]. So the type of the whole match is (Nothing => Future[MoneyType], MoneyType) which doesn't conform to sendMoney's argument type.

So the problem is that it's impossible to have a suitable common type for different combinations of sendMoney's arguments.

Henrik Sachse
  • 51,228
  • 7
  • 46
  • 59
Kolmar
  • 14,086
  • 1
  • 22
  • 25
  • Nice. But why isn't the common type as `MoneyType => Future[MoneyType]` . They have a common base class afterall – ffff Jan 13 '17 at 10:24
  • 1
    @FaizHalde Well, `HoldsMoney <: MoneyType`, `Future[HoldsMoney] <: Future[MoneyType]` (`Future` is covariant), but as I've mentioned `Function` is contravariant in its argument type, and so `HoldsMoney => Future[HoldsMoney]` is NOT a subtype of `MoneyType => Future[MoneyType]`. It may be counterintuitive, but it's actually quite natural when you think about it. Also see this question: http://stackoverflow.com/questions/10603982/why-is-function-a1-b-not-about-allowing-any-supertypes-as-parameters – Kolmar Jan 13 '17 at 10:30
  • Yes. The confusion is cleared now! Thanks. Seems like a impossibility to me – ffff Jan 13 '17 at 10:31
0

I think your goal is to refactor arguments creation for sendMoney and to pass them using tupled. I guess missing parts of your codes, and remove type bounds for simplicity.

def sendMoney(fn: (MoneyType) => Future[MoneyType], input: MoneyType): Unit = println("sendMoney")

def createHold(moneyType: MoneyType): Future[MoneyType] = ???
def createReserve(moneyType: MoneyType): Future[MoneyType] = ???

(sendMoney _).tupled(x match {
  case c: HoldsMoney => (createHold, c)
  case r: ReserveMoney => (createReserve, r)
})
NaHeon
  • 247
  • 1
  • 12