Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion docs/docs/reference/changed-features/eta-expansion-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -73,4 +73,4 @@ The method value syntax `m _` is deprecated.

## Reference

For more info, see [PR #2701](https://github.com/lampepfl/dotty/pull/2701).
For more information, see [PR #2701](https://github.com/lampepfl/dotty/pull/2701).
Original file line number Diff line number Diff line change
Expand Up @@ -119,4 +119,4 @@ Resolution](implicit-resolution.md) for more information.
For more information about implicit resolution, see [Changes in
Implicit Resolution](implicit-resolution.md).
Other details are available in
[PR #2065](https://github.com/lampepfl/dotty/pull/2065)
[PR #2065](https://github.com/lampepfl/dotty/pull/2065).
22 changes: 14 additions & 8 deletions docs/docs/reference/changed-features/main-functions.md
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,9 @@ title: "Main Methods"
---

Scala 3 offers a new way to define programs that can be invoked from the command line:
A `@main` annotation on a method turns this method into an executable program.
A `@main`{.scala} annotation on a method turns this method into an executable program.
Example:

```scala
@main def happyBirthday(age: Int, name: String, others: String*) =
val suffix =
Expand All @@ -21,18 +22,21 @@ Example:
for other <- others do bldr.append(" and ").append(other)
bldr.toString
```

This would generate a main program `happyBirthday` that could be called like this

```
> scala happyBirthday 23 Lisa Peter
Happy 23rd Birthday, Lisa and Peter!
```
A `@main` annotated method can be written either at the top-level or in a statically accessible object. The name of the program is in each case the name of the method, without any object prefixes. The `@main` method can have an arbitrary number of parameters.

A `@main`{.scala} annotated method can be written either at the top-level or in a statically accessible object. The name of the program is in each case the name of the method, without any object prefixes. The `@main`{.scala} method can have an arbitrary number of parameters.
For each parameter type there must be an instance of the `scala.util.FromString` type class
that is used to convert an argument string to the required parameter type.
The parameter list of a main method can end in a repeated parameter that then
takes all remaining arguments given on the command line.

The program implemented from a `@main` method checks that there are enough arguments on
The program implemented from a `@main`{.scala} method checks that there are enough arguments on
the command line to fill in all parameters, and that argument strings are convertible to
the required types. If a check fails, the program is terminated with an error message.

Expand All @@ -46,15 +50,16 @@ Illegal command line after first argument: more arguments expected
Illegal command line: java.lang.NumberFormatException: For input string: "sixty"
```

The Scala compiler generates a program from a `@main` method `f` as follows:
The Scala compiler generates a program from a `@main`{.scala} method `f` as follows:

- It creates a class named `f` in the package where the `@main` method was found
- It creates a class named `f` in the package where the `@main`{.scala} method was found
- The class has a static method `main` with the usual signature. It takes an `Array[String]`
as argument and returns `Unit`.
- The generated `main` method calls method `f` with arguments converted using
methods in the `scala.util.CommandLineParser` object.
methods in the [`scala.util.CommandLineParser` object](https://dotty.epfl.ch/api/scala/util/CommandLineParser$.html).

For instance, the `happyBirthDay` method above would generate additional code equivalent to the following class:

```scala
final class happyBirthday:
import scala.util.{CommandLineParser => CLP}
Expand All @@ -67,16 +72,17 @@ final class happyBirthday:
catch
case error: CLP.ParseError => CLP.showError(error)
```

**Note**: The `<static>` modifier above expresses that the `main` method is generated
as a static method of class `happyBirthDay`. It is not available for user programs in Scala. Regular "static" members are generated in Scala using objects instead.

`@main` methods are the recommended scheme to generate programs that can be invoked from the command line in Scala 3. They replace the previous scheme to write program as objects with a special `App` parent class. In Scala 2, `happyBirthday` could be written also like this:
`@main`{.scala} methods are the recommended scheme to generate programs that can be invoked from the command line in Scala 3. They replace the previous scheme to write program as objects with a special `App` parent class. In Scala 2, `happyBirthday` could be written also like this:

```scala
object happyBirthday extends App:
// needs by-hand parsing of arguments vector
...
```

The previous functionality of `App`, which relied on the "magic" `DelayedInit` trait, is no longer available. `App` still exists in limited form for now, but it does not support command line arguments and will be deprecated in the future. If programs need to cross-build
The previous functionality of `App`, which relied on the "magic" [`DelayedInit`](../dropped-features/delayed-init.md) trait, is no longer available. `App` still exists in limited form for now, but it does not support command line arguments and will be deprecated in the future. If programs need to cross-build
between Scala 2 and Scala 3, it is recommended to use an explicit `main` method with an `Array[String]` argument instead.
10 changes: 5 additions & 5 deletions docs/docs/reference/changed-features/match-syntax.md
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
---
layout: doc-page
title: Match Expressions
title: "Match Expressions"
---

The syntactical precedence of match expressions has been changed.
`match` is still a keyword, but it is used like an alphabetical operator. This has several consequences:
`match`{.scala} is still a keyword, but it is used like an alphabetical operator. This has several consequences:

1. `match` expressions can be chained:
1. `match`{.scala} expressions can be chained:

```scala
xs match {
Expand All @@ -29,7 +29,7 @@ The syntactical precedence of match expressions has been changed.
case "nonempty" => 1
```

2. `match` may follow a period:
2. `match`{.scala} may follow a period:

```scala
if xs.match
Expand All @@ -41,7 +41,7 @@ The syntactical precedence of match expressions has been changed.

3. The scrutinee of a match expression must be an `InfixExpr`. Previously the scrutinee could be
followed by a type ascription `: T`, but this is no longer supported. So `x : T match { ... }`
now has to be written `(x: T) match { ... }`.
now has to be written `(x: T) match { ... }`{.scala}.

## Syntax

Expand Down
9 changes: 6 additions & 3 deletions docs/docs/reference/changed-features/numeric-literals.md
Original file line number Diff line number Diff line change
@@ -1,14 +1,16 @@
---
layout: doc-page
title: Numeric Literals
title: "Numeric Literals"
---

**Note**: This feature is not yet part of the Scala 3 language definition. It can be made available by a language import:

```scala
import scala.language.experimental.genericNumberLiterals
```

In Scala 2, numeric literals were confined to the primitive numeric types `Int`, `Long`, `Float`, and `Double`. Scala 3 allows to write numeric literals also for user defined types. Example:
In Scala 2, numeric literals were confined to the primitive numeric types `Int`, `Long`, `Float`, and `Double`. Scala 3 allows to write numeric literals also for user-defined types. Example:

```scala
val x: Long = -10_000_000_000
val y: BigInt = 0x123_abc_789_def_345_678_901
Expand All @@ -17,6 +19,7 @@ val z: BigDecimal = 110_222_799_799.99
(y: BigInt) match
case 123_456_789_012_345_678_901 =>
```

The syntax of numeric literals is the same as before, except there are no pre-set limits
how large they can be.

Expand Down Expand Up @@ -63,7 +66,7 @@ gives a type error, since without an expected type `-10_000_000_000` is treated

### The FromDigits Trait

To allow numeric literals, a type simply has to define a `given` instance of the
To allow numeric literals, a type simply has to define a `given`{.scala} instance of the
`scala.util.FromDigits` type class, or one of its subclasses. `FromDigits` is defined
as follows:

Expand Down
20 changes: 15 additions & 5 deletions docs/docs/reference/changed-features/operators.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,14 @@ title: "Rules for Operators"

The rules for infix operators have changed in some parts:

First, an alphanumeric method can be used as an infix operator only if its definition carries an `infix` modifier. Second, it is recommended (but not enforced) to
augment definitions of symbolic operators with `@targetName` annotations. Finally,
First, an alphanumeric method can be used as an infix operator only if its definition carries an `infix`{.scala} modifier. Second, it is recommended (but not enforced) to
augment definitions of symbolic operators with `@targetName`{.scala} annotations. Finally,
a syntax change allows infix operators to be written on the left in a multi-line expression.

## The `infix` Modifier

An `infix` modifier on a method definition allows using the method as an infix operation. Example:
An `infix`{.scala} modifier on a method definition allows using the method as an infix operation. Example:

```scala
import scala.annotation.targetName

Expand Down Expand Up @@ -40,6 +41,7 @@ s1 * s2 // OK
s1 `*` s2 // also OK, but unusual
s1.*(s2) // also OK, but unusual
```

Infix operations involving alphanumeric operators are deprecated, unless
one of the following conditions holds:

Expand All @@ -52,8 +54,9 @@ any Unicode character `c` for which `java.lang.Character.isIdentifierPart(c)` re

Infix operations involving symbolic operators are always allowed, so `infix` is redundant for methods with symbolic names.

The `infix` modifier can also be given to a type:
```
The `infix`{.scala} modifier can also be given to a type:

```scala
infix type or[X, Y]
val x: String or Int = ...
```
Expand Down Expand Up @@ -107,6 +110,7 @@ It is recommended that definitions of symbolic operators carry a [`@targetName`
## Syntax Change

Infix operators can now appear at the start of lines in a multi-line expression. Examples:

```scala
val str = "hello"
++ " world"
Expand All @@ -117,6 +121,7 @@ def condition =
|| xs.exists(_ > 0)
|| xs.isEmpty
```

Previously, those expressions would have been rejected, since the compiler's semicolon inference
would have treated the continuations `++ " world"` or `|| xs.isEmpty` as separate statements.

Expand All @@ -133,19 +138,24 @@ Example:
freezing
| boiling
```

This is recognized as a single infix operation. Compare with:

```scala
freezing
!boiling
```

This is seen as two statements, `freezing` and `!boiling`. The difference is that only the operator in the first example
is followed by a space.

Another example:

```scala
println("hello")
???
??? match { case 0 => 1 }
```

This code is recognized as three different statements. `???` is syntactically a symbolic identifier, but
neither of its occurrences is followed by a space and a token that can start an expression.
7 changes: 5 additions & 2 deletions docs/docs/reference/changed-features/structural-types-spec.md
Original file line number Diff line number Diff line change
Expand Up @@ -30,9 +30,11 @@ the methods `selectDynamic` and `applyDynamic`. The methods could be members of

The `selectDynamic` method takes a field name and returns the value associated with that name in the `Selectable`.
It should have a signature of the form:

```scala
def selectDynamic(name: String): T
```

Often, the return type `T` is `Any`.

Unlike `scala.Dynamic`, there is no special meaning for an `updateDynamic` method.
Expand All @@ -41,10 +43,12 @@ Consequently, it is recommended not to define any member called `updateDynamic`

The `applyDynamic` method is used for selections that are applied to arguments. It takes a method name and possibly `Class`es representing its parameters types as well as the arguments to pass to the function.
Its signature should be of one of the two following forms:

```scala
def applyDynamic(name: String)(args: Any*): T
def applyDynamic(name: String, ctags: Class[?]*)(args: Any*): T
```

Both versions are passed the actual arguments in the `args` parameter. The second version takes in addition a vararg argument of `java.lang.Class`es that identify the method's parameter classes. Such an argument is needed
if `applyDynamic` is implemented using Java reflection, but it could be
useful in other cases as well. `selectDynamic` and `applyDynamic` can also take additional context parameters in using clauses. These are resolved in the normal way at the callsite.
Expand Down Expand Up @@ -94,5 +98,4 @@ conversion that can turn `v` into a `Selectable`, and the selection methods coul

## Context

For more info, see [Rethink Structural
Types](https://github.com/lampepfl/dotty/issues/1886).
For more information, see [Rethink Structural Types](https://github.com/lampepfl/dotty/issues/1886).
16 changes: 15 additions & 1 deletion docs/docs/reference/changed-features/structural-types.md
Original file line number Diff line number Diff line change
Expand Up @@ -32,19 +32,23 @@ configure how fields and methods should be resolved.
## Example

Here's an example of a structural type `Person`:

```scala
class Record(elems: (String, Any)*) extends Selectable:
private val fields = elems.toMap
def selectDynamic(name: String): Any = fields(name)

type Person = Record { val name: String; val age: Int }
```

The type `Person` adds a _refinement_ to its parent type `Record` that defines the two fields `name` and `age`. We say the refinement is _structural_ since `name` and `age` are not defined in the parent type. But they exist nevertheless as members of class `Person`. For instance, the following
program would print "Emma is 42 years old.":

```scala
val person = Record("name" -> "Emma", "age" -> 42).asInstanceOf[Person]
println(s"${person.name} is ${person.age} years old.")
```

The parent type `Record` in this example is a generic class that can represent arbitrary records in its `elems` argument. This argument is a
sequence of pairs of labels of type `String` and values of type `Any`.
When we create a `Person` as a `Record` we have to assert with a typecast
Expand All @@ -59,19 +63,22 @@ a method `selectDynamic`, which maps a field name to its value.
Selecting a structural type member is done by calling this method.
The `person.name` and `person.age` selections are translated by
the Scala compiler to:

```scala
person.selectDynamic("name").asInstanceOf[String]
person.selectDynamic("age").asInstanceOf[Int]
```

Besides `selectDynamic`, a `Selectable` class sometimes also defines a method `applyDynamic`. This can then be used to translate function calls of structural members. So, if `a` is an instance of `Selectable`, a structural call like `a.f(b, c)` would translate to

```scala
a.applyDynamic("f")(b, c)
```

## Using Java Reflection

Structural types can also be accessed using [Java reflection](https://www.oracle.com/technical-resources/articles/java/javareflection.html). Example:

```scala
type Closeable = { def close(): Unit }

Expand All @@ -81,14 +88,17 @@ Structural types can also be accessed using [Java reflection](https://www.oracle
class Channel:
def close(): Unit
```

Here, we define a structural type `Closeable` that defines a `close` method. There are various classes that have `close` methods, we just list `FileInputStream` and `Channel` as two examples. It would be easiest if the two classes shared a common interface that factors out the `close` method. But such factorings are often not possible if different libraries are combined in one application. Yet, we can still have methods that work on
all classes with a `close` method by using the `Closeable` type. For instance,

```scala
import scala.reflect.Selectable.reflectiveSelectable

def autoClose(f: Closeable)(op: Closeable => Unit): Unit =
try op(f) finally f.close()
```

The call `f.close()` has to use Java reflection to identify and call the `close` method in the receiver `f`. This needs to be enabled by an import
of `reflectiveSelectable` shown above. What happens "under the hood" is then the following:

Expand Down Expand Up @@ -122,6 +132,7 @@ the database access example given at the beginning of this document.

Local and anonymous classes that extend `Selectable` get more refined types
than other classes. Here is an example:

```scala
trait Vehicle extends reflect.Selectable:
val wheels: Int
Expand All @@ -132,12 +143,14 @@ val i3 = new Vehicle: // i3: Vehicle { val range: Int }

i3.range
```
The type of `i3` in this example is `Vehicle { val range: Int }`. Hence,

The type of `i3` in this example is `Vehicle { val range: Int }`{.scala}. Hence,
`i3.range` is well-formed. Since the base class `Vehicle` does not define a `range` field or method, we need structural dispatch to access the `range` field of the anonymous class that initializes `id3`. Structural dispatch
is implemented by the base trait `reflect.Selectable` of `Vehicle`, which
defines the necessary `selectDynamic` member.

`Vehicle` could also extend some other subclass of `scala.Selectable` that implements `selectDynamic` and `applyDynamic` differently. But if it does not extend a `Selectable` at all, the code would no longer typecheck:

```scala
trait Vehicle:
val wheels: Int
Expand All @@ -148,6 +161,7 @@ val i3 = new Vehicle: // i3: Vehicle

i3.range // error: range is not a member of `Vehicle`
```

The difference is that the type of an anonymous class that does not extend `Selectable` is just formed from the parent type(s) of the class, without
adding any refinements. Hence, `i3` now has just type `Vehicle` and the selection `i3.range` gives a "member not found" error.

Expand Down
2 changes: 1 addition & 1 deletion docs/docs/reference/changed-features/type-checking.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,4 @@ layout: doc-page
title: "Changes in Type Checking"
---

[//]: # todo: fill in
*** **TO BE FILLED IN** ***
5 changes: 4 additions & 1 deletion docs/docs/reference/changed-features/type-inference.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,4 +3,7 @@ layout: doc-page
title: "Changes in Type Inference"
---

See https://www.youtube.com/watch?v=lMvOykNQ4zs, https://www.youtube.com/watch?v=VV9lPg3fNl8.
For more information, see the two presentations

* [Scala 3, Type inference and You!](https://www.youtube.com/watch?v=lMvOykNQ4zs) by Guillaume Martres (September 2019)
* [GADTs in Dotty](https://www.youtube.com/watch?v=VV9lPg3fNl8) by Aleksander Boruch-Gruszecki (July 2019).
5 changes: 3 additions & 2 deletions docs/docs/reference/changed-features/wildcards.md
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,8 @@ for the type lambda `[X] =>> C[X]`. This makes higher-kinded types easier to use
parameter, `F[_]` means `F` is a type constructor whereas used as a type, `F[_]` means it is a wildcard (i.e. existential) type.
In the future, `F[_]` will mean the same thing, no matter where it is used.

We pick `?` as a replacement syntax for wildcard types, since it aligns with Java's syntax.
We pick `?` as a replacement syntax for wildcard types, since it aligns with
[Java's syntax](https://docs.oracle.com/javase/tutorial/java/generics/wildcardGuidelines.html).

### Migration Strategy

Expand All @@ -40,4 +41,4 @@ option `-Ykind-projector`:
available to rewrite one to the other.
3. In Scala 3.3, `*` is removed again, and all type parameter placeholders will be expressed with `_`.

These rules make it possible to cross build between Scala 2 using the kind projector plugin and Scala 3.0 - 3.2 using option `-Ykind-projector`.
These rules make it possible to cross build between Scala 2 using the kind projector plugin and Scala 3.0 - 3.2 using the compiler option `-Ykind-projector`.
Loading