Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

What is the FunctionN trait that represents a function taking a by-name parameter?

Tags:

scala

A function in Scala is an object that implements one of the FunctionN traits. For example:

scala> def f(x: Int) = x * x
f: (x: Int)Int

scala> val ff = f _
ff: Int => Int = <function1>

scala> val fff: Function1[Int, Int] = f _
fff: Int => Int = <function1>

So far, so good. But what if we have a function that takes a by-name parameter? It certainly does still implement one of the FunctionN traits:

scala> def g(x: => Int) = x * x
g: (x: => Int)Int

scala> val gg = g _
gg: => Int => Int = <function1>

scala> gg.isInstanceOf[Function1[_, _]]
res0: Boolean = true

But what type is it, exactly? It's not Function1[Int, Int]:

scala> val ggg: Function1[Int, Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: Int => Int
       val ggg: Function1[Int, Int] = g _
                                      ^

Nor is it Function1[Function0[Int], Int]:

scala> val ggg: Function1[Function0[Int], Int] = g _
<console>:8: error: type mismatch;
 found   : => Int => Int
 required: () => Int => Int
       val ggg: Function1[Function0[Int], Int] = g _
                                                 ^

And Function1[=> Int, Int] fails to compile:

scala> val ggg: Function1[=> Int, Int] = g _
<console>:1: error: identifier expected but '=>' found.
       val ggg: Function1[=> Int, Int] = g _
                          ^

So what is it?

like image 457
Paul Butcher Avatar asked Nov 24 '11 00:11

Paul Butcher


1 Answers

By-name is very useful but unsafe outside the type system

Scala by-name parameters are a syntactic sugar to make code more readable when lazy evaluation is needed. Without it we would need to put "() =>" in front of everything that needed to be lazy. That said, while it is just a function0 at runtime, it would be problematic at the typing system level if you could define anything other than a parameter as having a by-name type. Also remember that the FunctionN traits are there mostly for implementation and Java interoperability since there is no such thing as a function type in Java and the JVM.

Being explicit

If you do need to be explicit in your typing the following will allow you to be restrictive

def g(x: => Int) = x * x
val ggg: (=> Int) => Int = g _

More complex typing

The by-name typing can only be used inside the parameter portion of function type declarations. The function types themselves can then be used inside other parametrized types.

var funks: List[(=> Int) => Int] = Nil
funks ::= ggg
funks foreach { _ { println("hi"); 5 } }
like image 84
Neil Essy Avatar answered Sep 20 '22 14:09

Neil Essy