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

A and (=> A) do not unify when used as function type parameters #7431

Open
scabug opened this issue Apr 28, 2013 · 7 comments
Open

A and (=> A) do not unify when used as function type parameters #7431

scabug opened this issue Apr 28, 2013 · 7 comments

Comments

@scabug
Copy link

scabug commented Apr 28, 2013

It doesn't seem possible to use (=> A) => B in contexts requiring A => B:

scala> def log(a: => Any): Unit = println(a)
log: (a: => Any)Unit

scala> def apply[A, B](a: A)(f: A => B) = f(a)
apply: [A, B](a: A)(f: A => B)B

scala> apply("hello")(log)
<console>:10: error: type mismatch;
 found   : (=> Any) => Unit
 required: Int => ?
              apply("hello")(log)
                             ^

If you try to go the other direction, using A => B in contexts requiring (=> A) => B, the result depends on how you're trying to do it:

scala> def log(a: Any) = println(a)
log: (a: Any)Unit

scala> def apply[A, B](a: A)(f: (=> A) => B) = f(a)
apply: [A, B](a: A)(f: (=> A) => B)B

scala> apply("hello")(log)
<function0>

scala> apply("hello")(identity)
java.lang.ClassCastException: $anonfun$apply$1 cannot be cast to java.lang.String
@scabug
Copy link
Author

scabug commented Apr 28, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7431?orig=1
Reporter: Dan Rosen (mergeconflict)
Blocks #7430

@scabug
Copy link
Author

scabug commented Apr 28, 2013

@paulp said:
=> is underspecified so I'm guessing, but to use (=> A) => B where A => B is expected would imply either that A <:< (=> A), which can't be the case, or that there is something which automatically converts values of type (=> A) => B to values of type A => B, which there isn't unless you make one.

But you can make one.

scala> implicit def upgradeByName[A, B](x: (=> A) => B): A => B = (p: A) => x(p)
upgradeByName: [A, B](x: (=> A) => B)A => B

scala> apply("hello")(log)
hello

The other way is buggy as is clear from the CCE.

@scabug
Copy link
Author

scabug commented Apr 29, 2013

Dan Rosen (mergeconflict) said:
Yeah... I'd assumed that the value type A and parameterless method type => A were compatible or equivalent. The only thing in the spec that vaguely justifies that assumption is:

6.26.2: A parameterless method m of type => T is always converted to type T by evaluating the expression to which m is bound.

This is talking about the semantics of expression evaluation, though, not the typing rules...

@scabug
Copy link
Author

scabug commented Apr 29, 2013

@paulp said:
The key word is "converted".

@hrhino
Copy link
Member

hrhino commented Feb 22, 2018

Maybe this hasn't been fixed yet because it both should and should not compile.

I hear Kentucky Mule can do both in parallel.

@SethTisue SethTisue added this to the Backlog milestone Aug 25, 2022
@SethTisue
Copy link
Member

The situation doesn't seem to have changed in Scala 3. Even the ClassCastException remains reproducible.

@som-snytt
Copy link

Welcome to Scala 3.2.1-RC1-bin-SNAPSHOT-git-f0be00d (18.0.1.1, Java OpenJDK 64-Bit Server VM).
Type in expressions for evaluation. Or try :help.

scala> def log(a: Any) = println(a)
def log(a: Any): Unit

scala> def apply[A, B](a: A)(f: (=> A) => B) = f(a)
def apply[A, B](a: A)(f: (=> A) => B): B

scala> apply("hello")(log)
rs$line$2$$$Lambda$1434/0x00000008010b09c0@76e9eed8

scala> apply("hello")(identity)
val res0: String = hello

scala> def log(a: => Any): Unit = println(a)
def log(a: => Any): Unit

scala> def apply[A, B](a: A)(f: A => B) = f(a)
def apply[A, B](a: A)(f: A => B): B

scala> apply("hello")(log)
-- [E007] Type Mismatch Error: -----------------------------------------------------------------------------------------
1 |apply("hello")(log)
  |               ^^^
  |               Found:    (=> Any) => Unit
  |               Required: String => Unit
  |
  | longer explanation available when compiling with `-explain`
1 error found

scala> apply("hello")(log(_))
hello

or

Welcome to Scala 2.13.8 (OpenJDK 64-Bit Server VM, Java 18.0.1.1).
Type in expressions for evaluation. Or try :help.

scala> def log(a: => Any): Unit = println(a)
def log(a: => Any): Unit

scala>  def apply[A, B](a: A)(f: A => B) = f(a)
def apply[A, B](a: A)(f: A => B): B

scala> apply("hello")(log)
                      ^
       error: type mismatch;
        found   : (=> Any) => Unit
        required: String => ?

scala> apply("hello")(log(_))
hello

scala> def log(a: Any) = println(a)
def log(a: Any): Unit

scala> def apply[A, B](a: A)(f: (=> A) => B) = f(a)
def apply[A, B](a: A)(f: (=> A) => B): B

scala> apply("hello")(log)
$line8.$read$$iw$$Lambda$1126/0x00000008010c5578@70022d44

scala> apply("hello")(identity)
                      ^
       error: type mismatch;
        found   : String => String
        required: (=> String) => ?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

5 participants