Skip to content

Commit 069dd61

Browse files
committed
Update doc page
1 parent 7b2a785 commit 069dd61

File tree

1 file changed

+18
-21
lines changed

1 file changed

+18
-21
lines changed

docs/_docs/reference/experimental/modularity.md

Lines changed: 18 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -116,25 +116,22 @@ ClsParam ::= {Annotation} [{Modifier | ‘tracked’} (‘val’ | ‘var’)]
116116

117117
The (soft) `tracked` modifier is only allowed for `val` parameters of classes.
118118

119-
### Tracked inference
119+
### Tracked Inference
120120

121-
In some cases `tracked` can be infered and doesn't have to be written
122-
explicitly. A common such case is when a class parameter is referenced in the
123-
signatures of the public members of the class. e.g.
124-
```scala 3
125-
class OrdSet(val ord: Ordering) {
126-
type Set = List[ord.T]
127-
def empty: Set = Nil
121+
In some common cases the tracked modifier can be inferred, so it does not
122+
need to be written explicitly. Specifically, we infer `tracked` for a `val`
123+
parameter of a class if the formal parameter's type defines an abstract type member.
124+
This means that we do not lose information about how that member
125+
is defined in the actual argument passed to the class constructor.
128126

129-
implicit class helper(s: Set) {
130-
def add(x: ord.T): Set = x :: remove(x)
131-
def remove(x: ord.T): Set = s.filter(e => ord.compare(x, e) != 0)
132-
def member(x: ord.T): Boolean = s.exists(e => ord.compare(x, e) == 0)
133-
}
134-
}
127+
For instance, tracked `would` be inferred for the `SetFunctor` class
128+
we defined before, so we can also write it like this:
129+
```scala
130+
class SetFunctor(val ord: Ordering):
131+
type Set = List[ord.T]
132+
...
135133
```
136-
In the example above, `ord` is referenced in the signatures of the public
137-
members of `OrdSet`, so a `tracked` modifier will be inserted automatically.
134+
The `tracked` modifier on the `ord` parameter is inferred here, since `ord` is of type `Ordering`, which defines an abstract type member `T`.
138135

139136
Another common case is when a context bound has an associated type (i.e. an abstract type member) e.g.
140137
```scala 3
@@ -145,7 +142,7 @@ trait TC:
145142
class Klass[A: {TC as tc}]
146143
```
147144

148-
Here, `tc` is a context bound with an associated type `T`, so `tracked` will be inferred for `tc`.
145+
Here, `tc` is a context bound with an associated type `T`, so `tracked val` will be inferred for `tc` and the parameter will be represented as a field.
149146

150147
### Discussion
151148

@@ -160,10 +157,10 @@ If we assume `tracked` for parameter `x` (which is implicitly a `val`),
160157
then `foo` would get inferred type `Foo { val x: 1 }`, so it could not
161158
be reassigned to a value of type `Foo { val x: 2 }` on the next line.
162159

163-
Another approach might be to assume `tracked` for a `val` parameter `x`
164-
only if the class refers to a type member of `x`. But it turns out that this
165-
scheme is unimplementable since it would quickly lead to cyclic references
166-
when typechecking recursive class graphs. So an explicit `tracked` looks like the best available option.
160+
Another concern is that using tracked for all `val` parameters, including
161+
parameters of case classes could lead to large refinement types.
162+
163+
Therefore, inferring tracked only for parameters with types that define abstract members is a usable compromise. After all, if we did not infer `tracked` for these types, any references to the abstract type via a path would likely produce compilation errors.
167164

168165
## Tracked members
169166

0 commit comments

Comments
 (0)