Skip to content

Conversation

@Sporarum
Copy link
Contributor

@Sporarum Sporarum commented Sep 23, 2022

Edit: Other PRs have since modified this document, for the latest version, go here

We propose to extend eta-expansion to polymorphic methods.
This means automatically transforming polymorphic methods into corresponding polymorphic functions, for example:

def f1[A](x: A): A = ???
val v1_1: [B] => B => B = f1 // f1 becomes [B'] => (y: B') => f1[B'](y)
val v1_2                = f1 // f1 becomes [A'] => (x': A') => f1[A'](x')

(taken from Summary)

@Sporarum Sporarum changed the title SIP - Polymorphic Eta-Expansion SIP-49 - Polymorphic Eta-Expansion Sep 23, 2022
@julienrf
Copy link
Contributor

Thank you for your submision @Sporarum, I’ve assigned a team of reviewers to the proposal.

@julienrf
Copy link
Contributor

julienrf commented Oct 4, 2022

Dear reviewers, would you have time to review the proposal this week?

@soronpo
Copy link
Contributor

soronpo commented Oct 5, 2022

Yes, and I'm inclined to support its acceptance, but will need to re-read it over the weekend.

@lrytz
Copy link
Member

lrytz commented Oct 7, 2022

I support this proposal. I think it would be good if source/binary/tasty compatibility concerns could be better explained and illustrated.

@Sporarum
Copy link
Contributor Author

@soronpo Did you have a chance to re-read the proposal ?

@dragos I would be curious to have your opinion on this SIP

@lrytz I reworked the compatibility section with help from @sjrd, is the new one clearer ?

@lrytz
Copy link
Member

lrytz commented Oct 17, 2022

@lrytz I reworked the compatibility section with help from @sjrd, is the new one clearer ?

Yes, this is much more clear now, thank you!

// [T'] => (t: T') => [U'] => (u: U') => foo[T'](t)[U'](u)
~~~

#### Without expected type
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

To be safe I would strongly suggest that there should be no eta expansion without an expected type. The reason is that missing type parameters are always inferred and we do not want to make an exception now. Type arguments are in that sense analogous to implicits.

Here's an example:

def f(x: Int)(using C)

Here, f expands to

(x: Int) => f(x)(summon[C])

It does not expand to

(x: Int) => (c: C) ?=> m(x)(using c)

Analogously, when faced with

class C { type T }
def g(x: C)[U >: x.T]

g should expand to

(x: C) => g(x)[x.T]

and not to

(x: C) => [U] => g(x)[U]

Granted, the second version in the polymorphic eta expansion might seem more useful, (and maybe the second version for the implicit eta expansion is deemed more useful, too). But that's not how things work. I believe the analogy between polymorphic and implicit eta expansion is too strong to throw overboard.

Generally, I have a bit mixed feelings about this but am overall positive. The downside is that it is an "exotic" feature with not a lot of use cases, and the worked out definition is very complicated. This will have a significant impact on spec complexity. Do we really need it? On the positive side, the details are worked out very well. If we can restrict eta expansion to kick in only with a polymorphic expected type, I think it's fine. Otherwise the feature interactions with general inference principles of Scala are serious enough to hold back.

Also note that if we would decide at some point that we need eta expansion without an expected type because we have lots of convincing use cases, we can still add it later.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I ammended the proposal as requested, I will leave this conversation as unresolved so the reasons are apparent

@Sporarum Sporarum requested a review from odersky October 17, 2022 14:01
Copy link
Contributor

@odersky odersky left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the changes I think this is now good to go in.

@soronpo
Copy link
Contributor

soronpo commented Nov 8, 2022

I accept the amendment.
I think the proposal should also mention how this feature interacts with the interleaving clauses feature #47.

@julienrf
Copy link
Contributor

Hey @Sporarum, the proposal was discussed during the SIP meeting today. The Committee voted to accept the proposal, but they would like to see an example with a method that has interleaved parameter clauses in this section in addition to the extension method.

@julienrf
Copy link
Contributor

I went ahead and added the example myself to unblock the situation. Please adjust it if you feel it needs to be adjusted.

@julienrf julienrf merged commit 7fae918 into scala:main Nov 21, 2022
@julienrf
Copy link
Contributor

I have created an issue on the IntelliJ issue tracker to follow its progress: https://youtrack.jetbrains.com/issue/SCL-20759/Support-polymorphic-eta-expansion-SIP-49

Are there other tools that may be impacted by this SIP?

@Sporarum
Copy link
Contributor Author

@julienrf thank you for taking care of this while I was away

I do not believe any adjustments need to be made

The IntelliJ issue is incorrect however, the eta-expansion of v1_2 should not be changed by this SIP
This was a later change following this feedback:

To be safe I would strongly suggest that there should be no eta expansion without an expected type.

@julienrf
Copy link
Contributor

OK, thank you for proofreading, I’ve fixed the issue description on the IntelliJ tracker.

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

Projects

None yet

Development

Successfully merging this pull request may close these issues.

7 participants