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 should not precede empty application #7187

Closed
scabug opened this issue Feb 26, 2013 · 16 comments
Closed

eta expansion should not precede empty application #7187

scabug opened this issue Feb 26, 2013 · 16 comments

Comments

@scabug
Copy link

scabug commented Feb 26, 2013

There's no upside to it. Empty application cannot hurt eta expansion, but eta expansion can hurt empty application.

I propose the order in SLS 6.26.2 place "Empty Application" before "Eta Expansion".

scala> def f(): Map[Int, Int] = ???
f: ()Map[Int,Int]

scala> def g: Int => Int = f
<console>:8: error: type mismatch;
 found   : () => Map[Int,Int]
 required: Int => Int
       def g: Int => Int = f
                           ^

scala> def g: Map[Int, Int] = f
g: Map[Int,Int]

scala> class Bippy[A, B](f: A => B)
defined class Bippy

scala> def fn() = Map(1 -> 2)
fn: ()scala.collection.immutable.Map[Int,Int]

scala> new Bippy(fn)
<console>:10: error: type mismatch;
 found   : () => scala.collection.immutable.Map[Int,Int]
 required: ? => ?
              new Bippy(fn)
                        ^
@scabug
Copy link
Author

scabug commented Feb 26, 2013

Imported From: https://issues.scala-lang.org/browse/SI-7187?orig=1
Reporter: @paulp

@scabug
Copy link
Author

scabug commented Jun 11, 2013

@scabug
Copy link
Author

scabug commented Jun 11, 2013

@xeno-by said:
Seems related #6221

@scabug
Copy link
Author

scabug commented Feb 25, 2015

@retronym said:
The proposal can do more than make non-compiling code compile; it would change the semantics of:

object Test {
  def foo(): () => String = () => ""
  val f: () => Any = foo
 
  def main(args: Array[String]): Unit = {
    println(f()) // currently, <function0>, would be: ""
  }
}

I would argue that these are saner semantics, but we need to find a compatible path from here to there.

Perhaps we could deprecate and later remove eta expansion when the expected type is Function0. I wonder how much that comes up in the wild.

@scabug
Copy link
Author

scabug commented Feb 25, 2015

@retronym said:
Here's what I have in mind. I'll discuss this with Adriaan and Martin when we catch up at ScalaDays: https://github.com/retronym/scala/compare/ticket/7187?expand=1

@scabug
Copy link
Author

scabug commented Apr 23, 2015

@retronym said:
For sure we need to turn this off for SAMmy (#9178), but we didn't figure out the right approach for regular functions. I'm still in favour of leaving things in the order they stand, but phasing out type-driven eta expansion to F0. But I need to run an experiment with the community build to see if this is used much in the wild.

@scabug
Copy link
Author

scabug commented Apr 23, 2015

@som-snytt said (edited on Apr 23, 2015 4:48:55 PM UTC):
You deemed it puzzling on the other ticket, and in fact I did just briefly propose a puzzler scalapuzzlers/scalapuzzlers.github.com#121 where the charm lay in the method, which was a prefix operator (with empty param list). The OP didn't expect f(v) to behave differently from f(!v). If you keep F0 conversion, but try again with empty application in case of failure, then I'll reopen the puzzler.

@scabug
Copy link
Author

scabug commented Apr 24, 2015

@adriaanm said:
(Bumping priority to keep it high enough on my list...)

@scabug
Copy link
Author

scabug commented Apr 27, 2015

@demobox said (edited on Apr 27, 2015 1:49:12 PM UTC):
I'd agree that the proposed change would make things saner w.r.t. to alignment between parameterless methods and methods with an empty parameter list, so sounds like a good thing. Just wanted to point out that the description

There's no upside to it. Empty application cannot hurt eta expansion, but eta expansion can hurt empty application.

doesn't seem quite correct. E.g. here's an example (similar to the one @retronym gave in a previous comment) of code that would no longer compile:

class Gate {
  def unary_+(): Gate = this
}
val gate = new Gate
def foo(f: () => Gate) = 1

foo(+gate) // currently compiles but would fail if empty application were applied

@scabug
Copy link
Author

scabug commented Apr 27, 2015

@paulp said:
I don't really agree this invalidates that statement. Why would you define unary_+ with parentheses, other than the creation of new puzzlers? Do you really consider it an advantage that the expression +gate might be understood as Function0? I don't.

@scabug
Copy link
Author

scabug commented Apr 27, 2015

@demobox said:
> Do you really consider it an advantage that the expression +gate might be understood as Function0? I don't.

[~paulp]: I'd agree with that. My comment wasn't clear: I was only trying to point out that the proposed change could cause existing code to break/fail to compile.

The change itself seems desirable to me too - I don't see the current behaviour as an advantage.

@scabug
Copy link
Author

scabug commented Apr 27, 2015

@paulp said:
"could cause existing code to break/fail to compile"

Indeed. However that's true of every nontrivial change and most trivial ones. I intended the statement for a fictional universe in which sane semantics are a priority, and in that universe it doesn't come up that empty application can hurt eta-expansion because when it does it's a bug.

@scabug
Copy link
Author

scabug commented Aug 10, 2016

@lrytz said (edited on Aug 11, 2016 9:08:22 AM UTC):
scala/scala#5327

@scabug
Copy link
Author

scabug commented Sep 6, 2016

@adriaanm said:
I closed this one too soon -- it's only deprecated for now. We'll complete the change in 2.13

@adriaanm adriaanm added this to the 2.13.0-M4 milestone Jan 30, 2018
eed3si9n added a commit to eed3si9n/scala that referenced this issue Apr 8, 2018
Fixes scala/bug#7187

scala#5327 deprecates eta-expansion of zero-arg method values. This removes it in 2.13.
@lrytz lrytz modified the milestones: 2.13.0-M4, 2.13.0-M5 Apr 23, 2018
@adriaanm adriaanm modified the milestones: 2.13.0-M5, 2.13.0-RC1 Aug 8, 2018
@adriaanm
Copy link
Contributor

adriaanm commented Jan 8, 2019

Implemented under -Xsource:2.13 in scala/scala#6475

@adriaanm adriaanm added the has PR label Jan 8, 2019
adriaanm added a commit to adriaanm/scala that referenced this issue Jan 17, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)
  - 3.0: auto-application takes precedence, but otherwise we always eta-expand

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
@adriaanm
Copy link
Contributor

Changed my mind -- see scala/scala#7660

adriaanm added a commit to adriaanm/scala that referenced this issue Jan 17, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)
  - 3.0: auto-application takes precedence, but otherwise we always eta-expand

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
adriaanm added a commit to adriaanm/scala that referenced this issue Jan 17, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)
  - 3.0: auto-application takes precedence, but otherwise we always eta-expand

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 4, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)
  - 3.0: auto-application takes precedence, but otherwise we always eta-expand

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 5, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 5, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 5, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 5, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 8, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
adriaanm added a commit to adriaanm/scala that referenced this issue Feb 10, 2019
Reverse course from the deprecation introduced in 2.12.

(4.3) condition for eta-expansion by -Xsource level:

  - until 2.13:
    - for arity > 0: function or sam type is expected
    - for arity == 0: Function0 is expected -- SAM types do not eta-expand
      because it could be an accidental SAM scala/bug#9489
  - 2.14:
    - for arity > 0: unconditional
    - for arity == 0: a function-ish type of arity 0 is expected (including SAM)

warnings:
  - 2.12: eta-expansion of zero-arg methods was deprecated (scala/bug#7187)
  - 2.13: deprecation dropped in favor of setting the scene for uniform eta-expansion in 3.0
          warning still available under -Xlint:eta-zero
  - 2.14: expected type is a SAM that is not annotated with `@FunctionalInterface`
          if it's a Java-defined interface (under `-Xlint:eta-sam`)

(4.2) condition for auto-application by -Xsource level:

  - until 2.14: none (assuming condition for (4.3) was not met)
  - in 3.0: `meth.isJavaDefined`
    TODO decide -- currently the condition is more involved to give slack to
    Scala methods overriding Java-defined ones; I think we should resolve that
    by introducing slack in overriding e.g. a Java-defined `def toString()`
    by a Scala-defined `def toString`. This also works better for dealing
    with accessors overriding Java-defined methods.

    The current strategy in methodSig is problematic:
    > // Add a () parameter section if this overrides some method with () parameters
    > val vparamSymssOrEmptyParamsFromOverride =

    This means an accessor that overrides a Java-defined method gets a
    MethodType instead of a `NullaryMethodType`, which breaks lots of
    assumptions about accessors
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