Skip to content

Change to new given syntax #7210

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

Merged
merged 25 commits into from
Sep 17, 2019
Merged

Conversation

odersky
Copy link
Contributor

@odersky odersky commented Sep 12, 2019

@arturopala
Copy link
Contributor

I'm curious why the colon between identifier and curly brace?

@@ -152,14 +152,14 @@ object Instances extends Common {
object PostConditions {
opaque type WrappedResult[T] = T

private given WrappedResult {
private given extension WrappedResult: {
def apply[T](x: T): WrappedResult[T] = x
Copy link
Contributor

Choose a reason for hiding this comment

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

With the : the it starts looking a bit to similar to a structural type.

Copy link
Contributor

Choose a reason for hiding this comment

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

Do we really need the : here given that we already have the extension keyword?

@odersky
Copy link
Contributor Author

odersky commented Sep 12, 2019

I have now changed the syntax to

    given ops: extension { ... }

I believe that way it is more regular:

  • A named given always uses id : after the given keyword.
  • Use extension instead of a base class if you just define extension methods.

With collective extension parameters it's

    given ops: extension [T](x: S) { ... }

I believe that is clearer than the :-less alternative

   given extension ops[T](x: S) { ... }

This second alternative makes it look like ops is parameterized , which is wrong, of course.

@sake92
Copy link

sake92 commented Sep 13, 2019

Sorry if I misunderstand something, but comparing
implicit class Indexer[T](collection: Seq[T]) to
given extension Indexer[T](collection: Seq[T]),
they look kinda same right?

Why not have just extension keyword: extension Indexer[T](collection: Seq[T])?
And also anonymous extension[T](collection: Seq[T]), although it reads kinda weird... xD

@odersky
Copy link
Contributor Author

odersky commented Sep 13, 2019

The third variation of the theme drops the extension identifier again. So it's

    given { ... }

    given ops: { ... }

In the end, extension is unnecessary and risks being more confusing than enlightening.

  1. Adding extension makes it look like this is the standard way to specify extension methods. But that's not true. You can perfectly well implement a class and implement its extension methods or add new ones. I.e. the following also defines extension methods:
    given X {
      def (x: T) foo (y: T)
    }

If one adds an extension (since after all, there is an extension method, right?) the meaning changes in unintended ways:

    given extension X {
      def (x: T) foo (y: T)
    }

Now, X is the name of the extension itself instead of the name of the implemented class!

  1. Adding extension after the : is bad in a different way. Compare
    given foo: extension[T](x: T) { ... }

with

    given foo: extensn[T](x: T) { ... }

The two meanings are radically different. In the first case [T] and (x: T) bind new names whereas in the second case they are arguments that use existing names x and T. This is bad since extension has to be a soft keyword, so we cannot rely on syntax highlighting to show us the difference. It's also bad for a casual reader of Scala code who does not know that the identifier extension is used in this way. And, from a standpoint of grammar design I find it unappealing that the precise wording of an identifier determines whether what follows is a binding or using occurrence.

In the end, I believe it is better like this:

  • The name of a parent in a given can be left out, which means that we define only extension methods and nothing else.
  • In that case, if the extension method block { ... } is prefixed by a parameter list, that parameter list is applied as a prefix to each method in the extension block.

The rules are quite simple and clear that way.

@odersky odersky changed the title Change to new extension method syntax Change to new given syntax Sep 14, 2019
@odersky odersky force-pushed the new-given-syntax branch 4 times, most recently from 3d97e85 to 10668ab Compare September 15, 2019 20:17
It's

    given extension { ... }

or

    given extension ops: { ... }
Change from
```
given extension foo: { ... }
```
to
```
given foo: extension { ... }
```
The new syntax is more regular and pleasing to the eye. It avoids
the unusual `: { ... }` symbol combination.
We should get to a new stabilized "given" syntax first. Once that is done, shapeless can be updated
and re-integrated.
Drop `given match` and `implict match` syntax.
The docs on typeclass derivation still have to be updated to conform to the
new terminology.
We have a migration problem for implicit function types and closures. We cannot go
in one step from
```
given A => B
given (x: A) => B
```
to
```
(given A) => B
(given x: A) => B
```
because this becomes ambiguous inside parentheses.

We have to migrate using intermediate steps:

 1. re-allow delegate instead of given for these types and closures
 2. disallow given in the old position, and migrate all code over to delegate
 3. allow given in the new position.
 4. disallow delegate and migrate all code over to given in the new position.
Replace with `delegate A => B` in tests and with `ImplicitFunctionType[A, B]` in bootstrap code.
Also replace `given x: T => e` with `delegate x: T => e`, except in bootstrap code, where the
latter is not legal.

These measures are necessary for migration to new given scheme.
Drop given parameters that come after the implemented type, since these
will not be allowed in the future.

We cannot disable the feature right now, since bootstrap code uses it.
The chnages to imports broke the rename test outputs. We should come back o fix this.
I'll open an issue.
@nicolasstucki

This comment has been minimized.

@odersky
Copy link
Contributor Author

odersky commented Sep 17, 2019

This PR is maximally lenient, allowing all kinds of syntaxes:

  • the final given syntax
  • the previous given syntax with infix given and as
  • the delegate syntax

The reason is that bootstrap code currently uses both of the superseded styles. The idea is to merge this PR into the next bootstrap compiler. Then restrict everything to the new syntax and fix all code and remaining tests to conform to it.

To be able to remove remnants of the old given/delegate syntaxes.
@@ -171,7 +171,7 @@ class CommunityBuildTest {
extraSbtArgs = Seq("-Dscala.build.compileWithDotty=true")
)

@Test def shapeless = test(
/*@Test*/ def shapeless = test(
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO: Open an issue for this

@@ -89,7 +89,7 @@ class RenameTest {
testRenameFrom(m4)
}

@Test def renameRenamedImport: Unit = {
/*@Test*/ def renameRenamedImport: Unit = {
Copy link
Contributor

Choose a reason for hiding this comment

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

TODO create an issue to update these tests

@nicolasstucki nicolasstucki merged commit 3d7bb5b into scala:master Sep 17, 2019
@nicolasstucki nicolasstucki deleted the new-given-syntax branch September 17, 2019 12:11
nicolasstucki added a commit to scala/vscode-scala-syntax that referenced this pull request Sep 17, 2019
nicolasstucki added a commit to scala/vscode-scala-syntax that referenced this pull request Sep 17, 2019
Highlight the `given` in imports as a keyword and names as type entities.

As implemented in scala/scala3#7210
nicolasstucki added a commit to scala/vscode-scala-syntax that referenced this pull request Sep 17, 2019
Highlight the `given` in imports as a keyword and names as type entities.

* As implemented in scala/scala3#7210
* Also fixes scala/scala3#7233
@Mocuto
Copy link

Mocuto commented Sep 24, 2019

Where can I see the discussion for why the infix given notation was dropped? I very much preferred it over the change introduced in this PR and was surprised to see the latest Dotty release candidate drop it.

EDIT: #7151

@soronpo
Copy link
Contributor

soronpo commented Sep 24, 2019

@odersky Could you comment why use given and not extension here for extension methods? I'm not referring to given extension which is indeed redundant, but I don't understand why do we need given at all here.

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

Successfully merging this pull request may close these issues.

7 participants