-
Notifications
You must be signed in to change notification settings - Fork 51
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
Document migration to Scala 3 Underscore Type Lambdas syntax and cross-compiling with kind-projector #203
Merged
adpi2
merged 1 commit into
scalacenter:main
from
7mind:feature/kind-projector-migration-doc
May 12, 2021
Merged
Document migration to Scala 3 Underscore Type Lambdas syntax and cross-compiling with kind-projector #203
Changes from all commits
Commits
File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,117 @@ | ||
--- | ||
id: kind-projector | ||
title: kind-projector Migration Tutorial | ||
--- | ||
|
||
In the future, Scala 3 will use the `_` underscore symbol for placeholders in type lambdas — just as the underscore is currently used for placeholders in ordinary lambdas. | ||
|
||
The new type lambda syntax is not enabled by default, to enable it, use a compiler flag `-Ykind-projector:underscores`. Note that enabling underscore type lambdas will disable usage of `_` as a wildcard, you will only be able to write wildcards using the `?` symbol. | ||
|
||
If you wish to cross-compile a project for Scala 2 & Scala 3 while using Underscore Type Lambdas for both, you may do so starting with [kind-projector](https://github.com/typelevel/kind-projector) version `0.13.0` and up and Scala 2 versions `2.13.5` and `2.12.14`. | ||
To enable it, add the compiler flags `-Xsource:3 -P:kind-projector:underscore-placeholders` to your build. | ||
As in Scala 3, this will disable usage of `_` as a wildcard, however, the flag `-Xsource:3` will allow you to replace it with the `?` symbol. | ||
|
||
The following `sbt` configuration will set up the correct flags to cross-compile with new syntax: | ||
|
||
```scala | ||
ThisBuild / scalacOptions ++= (if (scalaVersion.value.startsWith("3")) Seq("-Ykind-projector:underscores") | ||
else Seq("-Xsource:3", "-P:kind-projector:underscore-placeholders")) | ||
``` | ||
|
||
### Migrating to New Syntax | ||
|
||
To use underscores for type-lambdas in existing kind-projector enabled code, replace `*` or `?` type lambda placeholders with `_`. | ||
|
||
In turn, you will also have to rewrite all usages of `_` as the wildcard to use `?` symbol. | ||
|
||
For example the following usage of the wildcard: | ||
|
||
```scala | ||
def getWidget(widgets: Set[_ <: Widget], name: String): Option[Widget] = widgets.find(_.name == name) | ||
``` | ||
|
||
Must be rewritten to: | ||
|
||
```scala | ||
def getWidget(widgets: Set[? <: Widget], name: String): Option[Widget] = widgets.find(_.name == name) | ||
``` | ||
|
||
And the following usages of kind-projector's `*` placeholder: | ||
|
||
```scala | ||
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double] | ||
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A] | ||
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B] | ||
``` | ||
|
||
Must be rewritten to: | ||
|
||
```scala | ||
Tuple2[_, Double] // equivalent to: type R[A] = Tuple2[A, Double] | ||
Either[Int, +_] // equivalent to: type R[+A] = Either[Int, A] | ||
Function2[-_, Long, +_] // equivalent to: type R[-A, +B] = Function2[A, Long, B] | ||
``` | ||
|
||
### Compiling Existing Code | ||
|
||
Even without migrating to Underscore type lambdas, you will likely be able to compile most of it with Scala 3 without changes. | ||
|
||
Use the flag `-Ykind-projector` to enable support for `*`-based type lambdas (without enabling underscore type lambdas), the following forms will now compile: | ||
|
||
```scala | ||
Tuple2[*, Double] // equivalent to: type R[A] = Tuple2[A, Double] | ||
Either[Int, +*] // equivalent to: type R[+A] = Either[Int, A] | ||
Function2[-*, Long, +*] // equivalent to: type R[-A, +B] = Function2[A, Long, B] | ||
``` | ||
|
||
### Rewriting Incompatible Constructs | ||
|
||
Scala 3's `-Ykind-projector` & `-Ykind-projector:underscores` implement only a subset of `kind-projector` syntax, in particular they do not implement: | ||
|
||
* higher-kinded type lambda placeholders | ||
* higher-kinded named type lambda parameters | ||
* The `Lambda` keyword (`λ` is still supported) | ||
|
||
You must rewrite ALL of the following forms: | ||
|
||
```scala | ||
// classic | ||
EitherT[*[_], Int, *] // equivalent to: type R[F[_], B] = EitherT[F, Int, B] | ||
// underscores | ||
EitherT[_[_], Int, _] // equivalent to: type R[F[_], B] = EitherT[F, Int, B] | ||
// named λ | ||
λ[(F[_], A) => EitherT[F, Int, A]] | ||
// named Lambda | ||
Lambda[(F[_], A) => EitherT[F, Int, A]] | ||
``` | ||
|
||
Into the following long-form to cross-compile with Scala 3: | ||
|
||
```scala | ||
type MyLambda[F[_], A] = EitherT[F, Int, A] | ||
MyLambda | ||
``` | ||
|
||
Alternatively you may use Scala 3's [Native Type Lambdas](https://dotty.epfl.ch/docs/reference/new-types/type-lambdas.html) if you do not need to cross-compile: | ||
|
||
```scala | ||
[F[_], A] =>> EitherT[F, Int, A] | ||
``` | ||
|
||
For `Lambda` you must rewrite the following form: | ||
|
||
```scala | ||
Lambda[(`+E`, `+A`) => Either[E, A]] | ||
``` | ||
|
||
To the following to cross-compile: | ||
|
||
λ[(`+E`, `+A`) => Either[E, A]] | ||
|
||
Or alternatively to Scala 3 Type Lambdas: | ||
|
||
```scala | ||
[E, A] =>> Either[E, A] | ||
``` | ||
|
||
Note: Scala 3 Type Lambdas no longer need `-` or `+` variance markers on parameters, these are now inferred. |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
In case are scalafix rules available for these rewrites, would be good to mention / link them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don' think we have a Scalafix rule but we have a compiler rewrite with
-source:future-migration -rewrite
.However, it also patches some other patterns that could break the compatibility with Scala 2.13. So I am not sure if it is worth mentioning.
I once did the inventory of the
-source:future-migration
rewrite rules but it has not been updated for some time: https://github.com/scalacenter/scala-3-migration-guide/tree/main/incompat-31