Skip to content

Commit dee0065

Browse files
authored
Integrate the trait parameters reference into the specification (#17393)
Work by @bishabosha
2 parents f8cb74e + d9fa877 commit dee0065

File tree

3 files changed

+110
-94
lines changed

3 files changed

+110
-94
lines changed

docs/_spec/05-classes-and-objects.md

Lines changed: 76 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -94,8 +94,10 @@ If this is not a template of a trait, then its _evaluation_ consists of the foll
9494

9595
- First, the superclass constructor ´sc´ is
9696
[evaluated](#constructor-invocations).
97-
- Then, all base classes in the template's [linearization](#class-linearization) up to the template's superclass denoted by ´sc´ are mixin-evaluated.
98-
Mixin-evaluation happens in reverse order of occurrence in the linearization.
97+
- Then, all base classes in the template's [linearization](#class-linearization) up to the template's superclass denoted by ´sc´ are evaluated.
98+
evaluation happens in reverse order of occurrence in the linearization. Each evaluation occurs as follows:
99+
- First, arguments to ´mt_i´ are evaluated from left to right, and set as parameters of ´mt_i´.
100+
- ´mt_i´ is then mixin-evaluated.
99101
- Finally, the statement sequence ´\mathit{stats}\,´ is evaluated.
100102

101103
### Constructor Invocations
@@ -664,13 +666,10 @@ This form of extensibility can be excluded by declaring the base class `Expr` `s
664666
## Traits
665667

666668
```ebnf
667-
TmplDef ::= ‘trait’ TraitDef
668-
TraitDef ::= id [TypeParamClause] TraitTemplateOpt
669-
TraitTemplateOpt ::= ‘extends’ TraitTemplate | [[‘extends’] TemplateBody]
669+
TmplDef ::= ‘trait’ ClassDef
670670
```
671671

672672
A _trait_ is a class that is meant to be added to some other class as a mixin.
673-
Unlike normal classes, traits cannot have constructor parameters.
674673
Furthermore, no constructor arguments are passed to the superclass of the trait.
675674
This is not necessary as traits are initialized after the superclass is initialized.
676675

@@ -745,9 +744,80 @@ object MyTable extends ListTable[String, Int](0) with SynchronizedTable[String,
745744
The object `MyTable` inherits its `get` and `set` method from `SynchronizedTable`.
746745
The `super` calls in these methods are re-bound to refer to the corresponding implementations in `ListTable`, which is the actual supertype of `SynchronizedTable` in `MyTable`.
747746

747+
### Extending parameterized traits
748+
749+
Extra rules apply for extending a trait with parameters:
750+
751+
1. If a class `´C´` extends a parameterized trait `´T´`, and its superclass does not, `´C´` _must_ pass arguments to `´T´`.
752+
753+
2. If a class `´C´` extends a parameterized trait `´T´`, and its superclass does as well, `´C´` _must not_ pass arguments to `´T´`.
754+
755+
3. Traits must never pass arguments to parent traits.
756+
757+
4. If a class `´C´` extends an unparameterized trait `´T_i´` and the base types of `´T_i´` include parameterized trait `´T_j´`, and the superclass of `´C´` does not extend `´T_j´`, then `´C´` _must_ also explicitly extend `´T_j´` and pass arguments.
758+
This rule is relaxed if the missing trait contains only context parameters. In that case the trait reference is implicitly inserted as an additional parent with inferred arguments.
759+
760+
###### Example - Preventing ambiguities
761+
762+
The following listing tries to extend `Greeting` twice, with different parameters.
763+
764+
```scala
765+
trait Greeting(val name: String):
766+
def msg = s"How are you, $name"
767+
768+
class C extends Greeting("Bob")
769+
770+
class D extends C, Greeting("Bill") // error
771+
772+
@main def greet = println(D().msg)
773+
```
774+
775+
Should this program print "Bob" or "Bill"? In fact this program is illegal, because it violates rule 2 above.
776+
Instead, `D` can extend `Greeting` without passing arguments.
777+
778+
###### Example - Overriding
779+
780+
Here's a variant of `Greeting` that overrides `msg`:
781+
```scala
782+
trait FormalGreeting extends Greeting:
783+
override def msg = s"How do you do, $name"
784+
```
785+
786+
Due to rule 4, the following class extending `FormalGreeting` is required to also extend `Greeting` with arguments:
787+
```scala
788+
class GreetBobFormally extends FormalGreeting, Greeting("Bob")
789+
```
790+
791+
###### Example - Inferred context parameters
792+
793+
Here's a variant of `Greeting` where the addressee is a context parameter of type `ImpliedName`:
794+
795+
```scala
796+
trait ImpliedGreeting(using val iname: ImpliedName):
797+
def msg = s"How are you, $iname"
798+
799+
case class ImpliedName(name: String):
800+
override def toString = name
801+
802+
trait ImpliedFormalGreeting extends ImpliedGreeting:
803+
override def msg = s"How do you do, $iname"
804+
805+
class F(using iname: ImpliedName) extends ImpliedFormalGreeting
806+
```
807+
808+
The definition of `F` in the last line is implicitly expanded to
809+
```scala
810+
class F(using iname: ImpliedName) extends
811+
Object, // implicitly inserted
812+
ImpliedGreeting(using iname), // implicitly inserted
813+
ImpliedFormalGreeting
814+
```
815+
Due to rule 4, `F` is required to also extend `ImpliedGreeting` and pass arguments to it, however note that because `ImpliedGreeting` has only context parameters the extension was added implicitly.
816+
748817
## Object Definitions
749818

750819
```ebnf
820+
TmplDef ::= ‘object’ ObjectDef
751821
ObjectDef ::= id ClassTemplate
752822
```
753823

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
---
2+
layout: doc-page
3+
title: "Trait Parameters"
4+
nightlyOf: https://docs.scala-lang.org/scala3/reference/other-new-features/trait-parameters.html
5+
---
6+
7+
Scala 3 enables traits to have parameters, just like a class.
8+
9+
For example, here is a trait `Greeting`:
10+
```scala
11+
trait Greeting(val name: String):
12+
def msg = s"How are you, $name"
13+
```
14+
15+
A class, enum, or object can extend `Greeting` as follows:
16+
17+
```scala
18+
class Greet extends Greeting("Bob"):
19+
println(msg)
20+
```
21+
22+
However if another trait extends `Greeting` then it must not pass arguments:
23+
24+
```scala
25+
trait FormalGreeting extends Greeting:
26+
override def msg = s"How do you do, $name"
27+
```
28+
29+
If you want a class to greet Bob formally, then you should extend both `FormalGreeting` and `Greeting`:
30+
31+
```scala
32+
class GreetFormally extends FormalGreeting, Greeting("Bob"):
33+
println(msg)
34+
```

docs/_spec/TODOreference/other-new-features/trait-parameters.md

Lines changed: 0 additions & 88 deletions
This file was deleted.

0 commit comments

Comments
 (0)