Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Eta-expansion for method with by-name parameter cannot be composed #11414

Open
JSantosP opened this Issue Feb 22, 2019 · 1 comment

Comments

Projects
None yet
2 participants
@JSantosP
Copy link

JSantosP commented Feb 22, 2019

Description:

When trying to compose functions, it is not allowed to use the result of eta-expansion for a method with by-name parameter. Should this be the expected behavior?

Scala version:

2.12.4

JDK version:

openjdk version "1.8.0_191"
OpenJDK Runtime Environment (build 1.8.0_191-8u191-b12-2ubuntu0.16.04.1-b12)
OpenJDK 64-Bit Server VM (build 25.191-b12, mixed mode)

Example:

scala> def foo(t: => Int): Option[Int] = Some(t)
foo: (t: => Int)Option[Int]

scala> def bar (t: String): Int = t.toInt 
bar: (t: String)Int

scala> val f: String => Option[Int] = bar _ andThen foo
<console>:137: error: type mismatch;
 found   : (=> Int) => Option[Int]
 required: Int => Option[Int]
       val f: String => Option[Int] = bar _ andThen foo

scala> val f: String => Option[Int] = foo _ compose bar
<console>:137: error: type mismatch;
 found   : Int
 required: => Int
       val f: String => Option[Int] = foo _ compose bar
@som-snytt

This comment has been minimized.

Copy link

som-snytt commented Feb 23, 2019

By-name params are a behavior of applications, but they also receive special treatment under eta-expansion:

scala> def f(i: => Int)(s: String) = s * i
f: (i: => Int)(s: String)String

scala> val g = f { println("Hi") ; 42 } _
g: String => String = $$Lambda$1904/318020776@1fd9893c

scala> g(".")
Hi
res0: String = ..........................................

It wouldn't be outrageous to offer an accommodation when the expected type has by-vals.

scala> def f(i: => Int) = i + i
f: (i: => Int)Int

scala> List(42).map(f)
                    ^
       error: type mismatch;
        found   : (=> Int) => Int
        required: Int => ?

scala> List(42).map(x => f(x))  // or map(f(_))
res2: List[Int] = List(84)

Is it more subtle than inlining:

scala> implicit def ups(f: ((=>Int) => Int)): (Int => Int) = x => f(x)
ups: (f: (=> Int) => Int)Int => Int

scala> List(42).map(f)
res3: List[Int] = List(84)

scala> def g(i: Int) = i + 1
g: (i: Int)Int

scala> g _ andThen f
res4: Int => Int = scala.Function1$$Lambda$2046/2116712126@24b8a393

It means losing a warning where you might assume more laziness:

scala> implicit def ups[A,R](f: ((=>A) => R)): (A => R) = x => f(x)
ups: [A, R](f: (=> A) => R)A => R

scala> import concurrent._,ExecutionContext.Implicits._
import concurrent._
import ExecutionContext.Implicits._

scala> def f(i: => Int) = i + i
f: (i: => Int)Int

scala> f { println("Hi") ; 42 }
Hi
Hi
res0: Int = 84

scala> val g = f _ andThen Future.apply[Int]
g: (=> Int) => scala.concurrent.Future[Int] = scala.Function1$$Lambda$2013/699026377@7fd2a67a

scala> g { println("Hi") ; 42 }
Hi
Hi
res2: scala.concurrent.Future[Int] = Future(<not completed>)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.