Skip to content

Remainder of the Spec updates about removals #16841

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 19 commits into from
May 1, 2023
Merged
Show file tree
Hide file tree
Changes from 17 commits
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
13 changes: 1 addition & 12 deletions docs/_spec/01-lexical-syntax.md
Original file line number Diff line number Diff line change
Expand Up @@ -259,7 +259,7 @@ A single new line token is accepted

## Literals

There are literals for integer numbers, floating point numbers, characters, booleans, symbols, strings.
There are literals for integer numbers, floating point numbers, characters, booleans, strings.
The syntax of these literals is in each case as in Java.

<!-- TODO
Expand All @@ -274,7 +274,6 @@ Literal ::= [‘-’] integerLiteral
| characterLiteral
| stringLiteral
| interpolatedString
| symbolLiteral
| ‘null’
```

Expand Down Expand Up @@ -490,16 +489,6 @@ In addition, Unicode escape sequences of the form `\uxxxx`, where each `x` is a

It is a compile time error if a backslash character in a character or string literal does not start a valid escape sequence.

### Symbol literals

```ebnf
symbolLiteral ::= ‘'’ plainid
```

A symbol literal `'x` is deprecated shorthand for the expression `scala.Symbol("x")`.

The `apply` method of `Symbol`'s companion object caches weak references to `Symbol`s, thus ensuring that identical symbol literals are equivalent with respect to reference equality.

## Whitespace and Comments

Tokens may be separated by whitespace characters and/or comments.
Expand Down
163 changes: 30 additions & 133 deletions docs/_spec/03-types.md

Large diffs are not rendered by default.

81 changes: 2 additions & 79 deletions docs/_spec/04-basic-declarations-and-definitions.md
Original file line number Diff line number Diff line change
Expand Up @@ -40,53 +40,15 @@ by commas. These are expanded according to the following scheme:
\VAL;x, y: T = e && \VAL; x: T = e \\
&& \VAL; y: T = x \\[0.5em]

\LET;x, y: T = e && \LET; x: T = e \\
&& \VAL; y: T = x \\[0.5em]

\DEF;x, y (ps): T = e &\tab\mbox{expands to}\tab& \DEF; x(ps): T = e \\
&& \DEF; y(ps): T = x(ps)\\[0.5em]

\VAR;x, y: T := e && \VAR;x: T := e\\
&& \VAR;y: T := x\\[0.5em]

\TYPE;t,u = T && \TYPE; t = T\\
&& \TYPE; u = t\\[0.5em]
\eda

All definitions have a ``repeated form`` where the initial
definition keyword is followed by several constituent definitions
which are separated by commas. A repeated definition is
always interpreted as a sequence formed from the
constituent definitions. E.g. the function definition
`def f(x) = x, g(y) = y` expands to
`def f(x) = x; def g(y) = y` and
the type definition
`type T, U <: B` expands to
`type T; type U <: B`.
}
\comment{
If an element in such a sequence introduces only the defined name,
possibly with some type or value parameters, but leaves out any
additional parts in the definition, then those parts are implicitly
copied from the next subsequent sequence element which consists of
more than just a defined name and parameters. Examples:

- []
The variable declaration `var x, y: Int`
expands to `var x: Int; var y: Int`.
- []

The value definition `val x, y: Int = 1`
expands to `val x: Int = 1; val y: Int = 1`.
- []
The class definition `case class X(), Y(n: Int) extends Z` expands to
`case class X extends Z; case class Y(n: Int) extends Z`.
- The object definition `case object Red, Green, Blue extends Color`~
expands to
```scala
case object Red extends Color
case object Green extends Color
case object Blue extends Color
```
-->

## Value Declarations and Definitions
Expand Down Expand Up @@ -647,49 +609,10 @@ By contrast, the following application is well formed and yields again the resul
sum(xs: _*)
```

### Procedures

```ebnf
FunDcl ::= FunSig
FunDef ::= FunSig [nl] ‘{’ Block ‘}’
```

Special syntax exists for procedures, i.e. methods that return the `Unit` value `()`.
A _procedure declaration_ is a method declaration where the result type is omitted.
The result type is then implicitly completed to the `Unit` type. E.g., `def ´f´(´\mathit{ps}´)` is equivalent to `def ´f´(´\mathit{ps}´): Unit`.

A _procedure definition_ is a method definition where the result type and the equals sign are omitted; its defining expression must be a block.
E.g., `def ´f´(´\mathit{ps}´) {´\mathit{stats}´}` is equivalent to `def ´f´(´\mathit{ps}´): Unit = {´\mathit{stats}´}`.

###### Example
Here is a declaration and a definition of a procedure named `write`:

```scala
trait Writer {
def write(str: String)
}
object Terminal extends Writer {
def write(str: String) { System.out.println(str) }
}
```

The code above is implicitly completed to the following code:

```scala
trait Writer {
def write(str: String): Unit
}
object Terminal extends Writer {
def write(str: String): Unit = { System.out.println(str) }
}
```

### Method Return Type Inference

A class member definition ´m´ that overrides some other method ´m'´ in a base class of ´C´ may leave out the return type, even if it is recursive.
In this case, the return type ´R'´ of the overridden method ´m'´, seen as a member of ´C´, is taken as the return type of ´m´ for each recursive invocation of ´m´.
That way, a type ´R´ for the right-hand side of ´m´ can be determined, which is then taken as the return type of ´m´.
Note that ´R´ may be different from ´R'´, as long as ´R´ conforms to ´R'´.
In this case, whether or not `m` is recursive, its return type will be the return type of ´m'´.

###### Example
Assume the following definitions:
Expand Down
63 changes: 1 addition & 62 deletions docs/_spec/05-classes-and-objects.md
Original file line number Diff line number Diff line change
Expand Up @@ -96,16 +96,6 @@ If this is not a template of a trait, then its _evaluation_ consists of the foll
Mixin-evaluation happens in reverse order of occurrence in the linearization.
- Finally, the statement sequence ´\mathit{stats}\,´ is evaluated.

###### Delayed Initialization
This statement sequence constitutes the initialization code for an object or class after the superclass constructor invocation and the mixin-evaluation of the template's base classes as described above.
Normally, this code is passed to a special hook, inaccessible to user code, which simply executes it.

However, in objects and classes (but not traits) which extend `scala.DelayedInit`, the initialization code is passed to a `delayedInit` method which can be overridden to implement arbitrary semantics.

```scala
def delayedInit(body: => Unit): Unit
```

### Constructor Invocations

```ebnf
Expand Down Expand Up @@ -305,57 +295,6 @@ It is a static error if the inheritance closure of a class type consists of an i

[^kennedy]: Kennedy, Pierce. [On Decidability of Nominal Subtyping with Variance.]( https://research.microsoft.com/pubs/64041/fool2007.pdf) in FOOL 2007

### Early Definitions

```ebnf
EarlyDefs ::= ‘{’ [EarlyDef {semi EarlyDef}] ‘}’ ‘with’
EarlyDef ::= {Annotation} {Modifier} PatVarDef
```

A template may start with an _early field definition_ clause, which serves to define certain field values before the supertype constructor is called.
In a template

```scala
{ val ´p_1´: ´T_1´ = ´e_1´
...
val ´p_n´: ´T_n´ = ´e_n´
} with ´sc´ with ´mt_1´ with ´mt_n´ { ´\mathit{stats}´ }
```

The initial pattern definitions of ´p_1 , \ldots , p_n´ are called _early definitions_.
They define fields which form part of the template.
Every early definition must define at least one variable.

An early definition is type-checked and evaluated in the scope which is in effect just before the template being defined, augmented by any type parameters of the enclosing class and by any early definitions preceding the one being defined.
In particular, any reference to `this` in an early definition refers to the identity of `this` just outside the template.
Consequently, it is impossible for an early definition to refer to the object being constructed by the template, or to refer to one of its fields and methods, except for any other preceding early definition in the same section.
Furthermore, references to preceding early definitions always refer to the value that's defined there and do not take into account overriding definitions.
In other words, a block of early definitions is evaluated exactly as if it were a local block containing a number of value definitions.

Early definitions are evaluated before the superclass constructor of the template is called, in the order they are defined.

###### Example
Early definitions are particularly useful for traits, which do not have normal constructor parameters.
Example:

```scala
trait Greeting {
val name: String
val msg = "How are you, "+name
}
class C extends {
val name = "Bob"
} with Greeting {
println(msg)
}
```

In the code above, the field `name` is initialized before the constructor of `Greeting` is called.
Therefore, field `msg` in class `Greeting` is properly initialized to `"How are you, Bob"`.

If `name` had been initialized instead in `C`'s normal class body, it would be initialized after the constructor of `Greeting`.
In that case, `msg` would be initialized to `"How are you, <null>"`.

## Modifiers

```ebnf
Expand Down Expand Up @@ -602,7 +541,7 @@ A constructor expression is either a self constructor invocation `this(´\mathit
The self constructor invocation must construct a generic instance of the class.
I.e. if the class in question has name ´C´ and type parameters `[´\mathit{tps}\,´]`, then a self constructor invocation must generate an instance of `´C´[´\mathit{tps}\,´]`; it is not permitted to instantiate formal type parameters.

The signature and the self constructor invocation of a constructor definition are type-checked and evaluated in the scope which is in effect at the point of the enclosing class definition, augmented by any type parameters of the enclosing class and by any [early definitions](#early-definitions) of the enclosing template.
The signature and the self constructor invocation of a constructor definition are type-checked and evaluated in the scope which is in effect at the point of the enclosing class definition, augmented by any type parameters of the enclosing class.
The rest of the constructor expression is type-checked and evaluated as a method body in the current class.

If there are auxiliary constructors of a class ´C´, they form together with ´C´'s primary [constructor](#class-definitions) an overloaded constructor definition.
Expand Down
60 changes: 23 additions & 37 deletions docs/_spec/06-expressions.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,6 @@ Expr ::= (Bindings | id | ‘_’) ‘=>’ Expr
Expr1 ::= ‘if’ ‘(’ Expr ‘)’ {nl} Expr [[semi] ‘else’ Expr]
| ‘while’ ‘(’ Expr ‘)’ {nl} Expr
| ‘try’ Expr [‘catch’ Expr] [‘finally’ Expr]
| ‘do’ Expr [semi] ‘while’ ‘(’ Expr ‘)’
| ‘for’ (‘(’ Enumerators ‘)’ | ‘{’ Enumerators ‘}’) {nl} [‘yield’] Expr
| ‘throw’ Expr
| ‘return’ [Expr]
Expand Down Expand Up @@ -60,6 +59,7 @@ When we write "expression ´e´ is expected to conform to type ´T´", we mean:
The following skolemization rule is applied universally for every expression:
If the type of an expression would be an existential type ´T´, then the type of the expression is assumed instead to be a [skolemization](03-types.html#existential-types) of ´T´.

<!-- TODO: Replace by description of Scala 3 skolemization -->
Skolemization is reversed by type packing.
Assume an expression ´e´ of type ´T´ and let ´t_1[\mathit{tps}\_1] >: L_1 <: U_1, ..., t_n[\mathit{tps}\_n] >: L_n <: U_n´ be all the type variables created by skolemization of some part of ´e´ which are free in ´T´.
Then the _packed type_ of ´e´ is
Expand Down Expand Up @@ -201,8 +201,8 @@ ArgumentExprs ::= ‘(’ [Exprs] ‘)’
Exprs ::= Expr {‘,’ Expr}
```

An application `´f(e_1, ..., e_m)´` applies the expression `´f´` to the argument expressions `´e_1, ..., e_m´`.
For the overal expression to be well-typed, ´f´ must be *applicable* to its arguments, which is defined next by case analysis on ´f´'s type.
An application `´f(e_1, ..., e_m)´` applies the method `´f´` to the argument expressions `´e_1, ..., e_m´`.
For this expression to be well-typed, the method must be *applicable* to its arguments:

If ´f´ has a method type `(´p_1´:´T_1, ..., p_n´:´T_n´)´U´`, each argument expression ´e_i´ is typed with the corresponding parameter type ´T_i´ as expected type.
Let ´S_i´ be the type of argument ´e_i´ ´(i = 1, ..., m)´.
Expand All @@ -214,12 +214,12 @@ Once the types ´S_i´ have been determined, the method ´f´ of the above metho
- for every positional argument ´e_i´ the type ´S_i´ is [compatible](03-types.html#compatibility) with ´T_i´;
- if the expected type is defined, the result type ´U´ is [compatible](03-types.html#compatibility) to it.

If ´f´ is a polymorphic method, [local type inference](#local-type-inference) is used to instantiate ´f´'s type parameters.
The polymorphic method is applicable if type inference can determine type arguments so that the instantiated method is applicable.

If ´f´ has some value type, the application is taken to be equivalent to `´f´.apply(´e_1, ..., e_m´)`, i.e. the application of an `apply` method defined by ´f´.
The value `´f´` is applicable to the given arguments if `´f´.apply` is applicable.
If ´f´ is instead of some value type, the application is taken to be equivalent to `´f´.apply(´e_1, ..., e_m´)`, i.e. the application of an `apply` method defined by ´f´.
Value `´f´` is applicable to the given arguments if `´f´.apply` is applicable.

Note:
In the case where ´f´ or `´f´.apply` is a polymorphic method, this is taken as an [ommitted type application](#type-applications).
`´f´` is applicable to the given arguments if the result of this type application is applicable.

The application `´f´(´e_1, ..., e_n´)` evaluates ´f´ and then each argument ´e_1, ..., e_n´ from left to right, except for arguments that correspond to a by-name parameter (see below).
Each argument expression is converted to the type of its corresponding formal parameter.
Expand Down Expand Up @@ -381,9 +381,15 @@ Type applications can be omitted if [local type inference](#local-type-inference
```ebnf
SimpleExpr ::= ‘(’ [Exprs] ‘)’
```
A _tuple expression_ `(´e_1´, ..., ´e_n´)` where ´n \geq 2´ is equivalent to the expression `´e_1´ *: ... *: ´e_n´ *: scala.EmptyTuple`.

Note:
As calls to `*:` are slow, a more efficient translation is free to be implemented.
For example, `(´e_1´, ´e_2´)` could be translated to `scala.Tuple2(´e_1´, ´e_2´)`, which is indeed equivalent to `´e_1´ *: ´e_2´ *: scala.EmptyTuple`.

A _tuple expression_ `(´e_1´, ..., ´e_n´)` is an alias for the class instance creation `scala.Tuple´n´(´e_1´, ..., ´e_n´)`, where ´n \geq 2´.
The empty tuple `()` is the unique value of type `scala.Unit`.
Note:
The expression `(´e_1´)` is not equivalent to `´e_1´ *: scala.EmptyTuple`, but instead a regular parenthesized expression.
The expression `()` is not an alias for `scala.EmptyTuple`, but instead the unique value of type `scala.Unit`.

## Instance Creation Expressions

Expand Down Expand Up @@ -455,6 +461,7 @@ The final expression can be omitted, in which case the unit value `()` is assume
The expected type of the final expression ´e´ is the expected type of the block.
The expected type of all preceding statements is undefined.

<!-- TODO: Rewrite when type avoidance section is done -->
The type of a block `´s_1´; ...; ´s_n´; ´e´` is `´T´ forSome {´\,Q\,´}`, where ´T´ is the type of ´e´ and ´Q´ contains [existential clauses](03-types.html#existential-types) for every value or type name which is free in ´T´ and which is defined locally in one of the statements ´s_1, ..., s_n´.
We say the existential clause _binds_ the occurrence of the value or type name.
Specifically,
Expand All @@ -468,23 +475,7 @@ It is an error if ´c´ carries type parameters.

Evaluation of the block entails evaluation of its statement sequence, followed by an evaluation of the final expression ´e´, which defines the result of the block.

A block expression `{´c_1´; ...; ´c_n´}` where ´s_1, ..., s_n´ are case clauses forms a [pattern matching anonymous function](08-pattern-matching.html#pattern-matching-anonymous-functions).

###### Example
Assuming a class `Ref[T](x: T)`, the block

```scala
{ class C extends B {´\ldots´} ; new Ref(new C) }
```

has the type `Ref[_1] forSome { type _1 <: B }`.
The block

```scala
{ class C extends B {´\ldots´} ; new C }
```

simply has type `B`, because with the rules [here](03-types.html#simplification-rules) the existentially quantified type `_1 forSome { type _1 <: B }` can be simplified to `B`.
A block expression `{´c_1´; ...; ´c_n´}` where ´c_1, ..., c_n´ are case clauses forms a [pattern matching anonymous function](08-pattern-matching.html#pattern-matching-anonymous-functions).

## Prefix, Infix, and Postfix Operations

Expand Down Expand Up @@ -717,15 +708,6 @@ def whileLoop(cond: => Boolean)(body: => Unit): Unit =
if (cond) { body ; whileLoop(cond)(body) } else {}
```

## Do Loop Expressions

```ebnf
Expr1 ::= ‘do’ Expr [semi] ‘while’ ‘(’ Expr ‘)’
```

The _do loop expression_ `do ´e_1´ while (´e_2´)` is typed and evaluated as if it was the expression `(´e_1´ ; while (´e_2´) ´e_1´)`.
A semicolon preceding the `while` symbol of a do loop expression is ignored.

## For Comprehensions and For Loops

```ebnf
Expand Down Expand Up @@ -933,6 +915,9 @@ Binding ::= (id | ‘_’) [‘:’ Type]
The anonymous function of arity ´n´, `(´x_1´: ´T_1, ..., x_n´: ´T_n´) => e` maps parameters ´x_i´ of types ´T_i´ to a result given by expression ´e´.
The scope of each formal parameter ´x_i´ is ´e´.
Formal parameters must have pairwise distinct names.
Type bindings can be omitted, in which case the compiler will attempt to infer valid bindings.

Note: `() => ´e´` defines a nullary function (´n´ = 0), and not for example `(_: Unit) => ´e´`.

In the case of a single untyped formal parameter, `(´x\,´) => ´e´` can be abbreviated to `´x´ => ´e´`.
If an anonymous function `(´x´: ´T\,´) => ´e´` with a single typed parameter appears as the result expression of a block, it can be abbreviated to `´x´: ´T´ => e`.
Expand Down Expand Up @@ -982,7 +967,7 @@ x => x // The identity function

f => g => x => f(g(x)) // Curried function composition

(x: Int,y: Int) => x + y // A summation function
(x: Int, y: Int) => x + y // A summation function

() => { count += 1; count } // The function which takes an
// empty parameter list ´()´,
Expand Down Expand Up @@ -1200,6 +1185,7 @@ question: given
- A parameterized method ´m´ of type `(´p_1:T_1, ..., p_n:T_n´)´U´` is _as specific as_ some other member ´m'´ of type ´S´ if ´m'´ is [applicable](#method-applications) to arguments `(´p_1, ..., p_n´)` of types ´T_1, ..., T_n´.
- A polymorphic method of type `[´a_1´ >: ´L_1´ <: ´U_1, ..., a_n´ >: ´L_n´ <: ´U_n´]´T´` is as specific as some other member of type ´S´ if ´T´ is as specific as ´S´ under the assumption that for ´i = 1, ..., n´ each ´a_i´ is an abstract type name bounded from below by ´L_i´ and from above by ´U_i´.
- A member of any other type is always as specific as a parameterized method or a polymorphic method.
<!-- TODO: check the following, as it reduces to "the member of type ´T´ is as specific as the member of type ´U´ if the ´T´ conforms to ´U´." -->
- Given two members of types ´T´ and ´U´ which are neither parameterized nor polymorphic method types, the member of type ´T´ is as specific as the member of type ´U´ if the existential dual of ´T´ conforms to the existential dual of ´U´.
Here, the existential dual of a polymorphic type `[´a_1´ >: ´L_1´ <: ´U_1, ..., a_n´ >: ´L_n´ <: ´U_n´]´T´` is `´T´ forSome { type ´a_1´ >: ´L_1´ <: ´U_1´, ..., type ´a_n´ >: ´L_n´ <: ´U_n´}`.
The existential dual of every other type is the type itself.
Expand Down
Loading