Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Implicit conversion of a function to a second-order-function only works if the function to convert has at least two parameters

I have a problem of implicit conversions and higher-order functions. It seems that an implicit conversions of a function to a second-order-function only works, if the function to convert has at least two parameters.

Works:

implicit def conv(foo: Integer => String): String => String = null

Does not work:

implicit def conv(foo: Integer => String): String => String => String = null

Works:

implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

Full example with point of failure:

{
    implicit def conv(foo: Integer => String): String => String = null

    def baadf00d(foo: Integer): String = null

    def deadbeef(foo: String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d)
}

{
    implicit def conv(foo: Integer => String): String => String => String = null

    def baadf00d(foo: Integer): String = null

    def deadbeef(foo: String => String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d) // <-------- DOES NOT COMPILE!
}

{
    implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

    def baadf00d(foo: Integer, bar: Integer): String = null

    def deadbeef(foo: String => String => String) = null

    deadbeef(conv(baadf00d))

    deadbeef(baadf00d)
}

What am I missing?

Thanks!

like image 293
user3612643 Avatar asked Feb 11 '15 13:02

user3612643


1 Answers

  implicit def conv(foo: Integer => String): String => String => String = ???

  def baadf00d(i: Integer): String = ???
  def goodf00d: Integer => String = _ => ???

  def deadbeef(foo: String => String => String) = ???

  deadbeef(conv(baadf00d))

  deadbeef(baadf00d) // <-------- DOES NOT COMPILE!
  deadbeef(goodf00d) // <-------- COMPILE!
  // ¯\_(ツ)_/¯

The issue is how implicit conversions work on Scala and the fact that there are curried and uncurried functions in Scala.

This is something that SHOULD work but doesn't and is probably just yet another compiler bug (get ready to meet many more as you use Scala more and more).

EDIT: As for your last example

implicit def conv(foo: (Integer, Integer) => String): String => String => String = null

def baadf00d(foo: Integer, bar: Integer): String = null

def deadbeef(foo: String => String => String) = null

That's because there the function definitions do match. The conv expects a function (Int, Int) => String and a normal method definition (uncurried) in scala, like how baadf00d is defined, turns into that.

For example, a function:

def f(a: Int, b: Int): String

Gets turned into a

(Int, Int) => String

Notice that the 2 Ints are tupled! This is NOT the same as:

Int => Int => String

If you were to redefine baadf00d into:

def baadf00d: Integer => Integer => String = _ => _ => ???

That code won't compile, because baadf00d is now "different", even though it is doing the same thing.

For more information, look at the definition of the objects:

Function1, Function2, Function3 ....

http://www.scala-lang.org/api/current/#scala.Function2

like image 98
Nacht Avatar answered Nov 15 '22 09:11

Nacht