0

I've written a simple code in Scala with implicit conversion of Function1 to some case class.

object MyApp extends App{
  case class FunctionContainer(val function:AnyRef)

  implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)

  def someFunction(i:Int):String = "someString"
  def abc(f : FunctionContainer):String = "abc"

  println(abc(someFunction))
} 

But it doesn't work. Compiler doesn't want to pass someFunction as an argument to abc. I can guess its reasons but don't know exactly why it doesn't work.

  • 1
    See [this question](http://stackoverflow.com/questions/2529184/difference-between-method-and-function-in-scala) for the difference between a method and a function in Scala. – Peter Neyens Oct 26 '15 at 21:46

3 Answers3

3

Your someFunction appears as a method here. You could try either

object MyApp extends App{
  case class FunctionContainer(val function:AnyRef)

  implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)

  val someFunction = (i:Int) => "someString"
  def abc(f : FunctionContainer):String = "abc"

  println(abc(someFunction))
}

or

object MyApp extends App{
  case class FunctionContainer(val function:AnyRef)

  implicit def cast(function1: Int => String):FunctionContainer = new FunctionContainer(function1)

  def someFunction(i:Int): String = "someString"
  def abc(f : FunctionContainer):String = "abc"

  println(abc(someFunction(_: Int)))
}

By the way: implicitly casting such common functions to something else can quickly lead to problems. Are you absolutely sure that you need this? Wouldn't it be easier to overload abc?

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
3

When you use a method name as you have, the compiler has to pick how to convert the method type to a value. If the expected type is a function, then it eta-expands; otherwise it supplies empty parens to invoke the method. That is described here in the spec.

But it wasn't always that way. Ten years ago, you would have got your function value just by using the method name.

The new online spec omits the "Change Log" appendix, so for the record, here is the moment when someone got frustrated with parens and introduced the current rules. (See Scala Reference 2.9, page 181.)

This has not eliminated all irksome anomalies.

Conversions

The rules for implicit conversions of methods to functions (§6.26) have been tightened. Previously, a parameterized method used as a value was always implicitly converted to a function. This could lead to unexpected results when method arguments were forgotten. Consider for instance the statement below:

show(x.toString)

where show is defined as follows:

def show(x: String) = Console.println(x)

Most likely, the programmer forgot to supply an empty argument list () to toString. The previous Scala version would treat this code as a partially applied method, and expand it to:

show(() => x.toString())

As a result, the address of a closure would be printed instead of the value of s. Scala version 2.0 will apply a conversion from partially applied method to function value only if the expected type of the expression is indeed a function type. For instance, the conversion would not be applied in the code above because the expected type of show’s parameter is String, not a function type. The new convention disallows some previously legal code. Example:

def sum(f: int => double)(a: int, b: int): double =
  if (a > b) 0 else f(a) + sum(f)(a + 1, b)

val sumInts = sum(x => x) // error: missing arguments

The partial application of sum in the last line of the code above will not be converted to a function type. Instead, the compiler will produce an error message which states that arguments for method sum are missing. The problem can be fixed by providing an expected type for the partial application, for instance by annotating the definition of sumInts with its type:

val sumInts: (int, int) => double = sum(x => x) // OK

On the other hand, Scala version 2.0 now automatically applies methods with empty parameter lists to () argument lists when necessary. For instance, the show expression above will now be expanded to

show(x.toString())
som-snytt
  • 39,429
  • 2
  • 47
  • 129
2

You should use eta-expansion

println(abc(someFunction _))
Archeg
  • 8,364
  • 7
  • 43
  • 90