What is the FunctionN function representing a function with a by-name parameter?

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

 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 still implements one of the features of FunctionN :

 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 which type, exactly? This is 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 _ ^ 

And this is not 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] failed 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?

+6
source share
2 answers

By name is very useful, but unsafe outside the type system.

Scala by-name parameters are syntactic sugar to make code more readable when lazy evaluation is required. Without this, we would have to put "() =>" in front of everything that should have been lazy. However, although it is just a function at run time, it would be problematic at the input system level if you could define anything other than a parameter as having a type by name. Also remember that FunctionN functions exist primarily for implementation and compatibility with Java, as there is no such function as function type in Java and JVM.

Explicit

If you need to be explicit as you type, the following will limit you

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

More complex typing

Typical encryption can only be used inside a part of a function type declaration parameter. Then the function types themselves can be used inside other parameterized types.

 var funks: List[(=> Int) => Int] = Nil funks ::= ggg funks foreach { _ { println("hi"); 5 } } 
+4
source

Rex Kerr answers this question and gives you a hint: the by-name argument eventually converts to Function0 , but is probably considered specifically at compile time.

You can check this out:

 scala> gg(sys.error("me")) java.lang.RuntimeException: me at scala.sys.package$.error(package.scala:27) at $anonfun$1.apply(<console>:10) at $anonfun$1.apply(<console>:10) at scala.Function0$class.apply$mcI$sp(Function0.scala:34) at scala.runtime.AbstractFunction0.apply$mcI$sp ... 

EDIT

To expand on my first comment, this also indicates that you cannot specify a type for the by-name parameter:

 def test[A: Manifest](fun: Function1[A, Int]): Unit = println("Found " + implicitly[Manifest[A]]) scala> test(gg) <console>:11: error: No Manifest available for => Int. test(gg) ^ 
+1
source

Source: https://habr.com/ru/post/902266/


All Articles