Skip to content

Commit 4b03873

Browse files
committed
Update doc page
1 parent 3edb4bf commit 4b03873

File tree

2 files changed

+26
-12
lines changed

2 files changed

+26
-12
lines changed

docs/_docs/reference/experimental/capture-checking/mutability.md

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -239,6 +239,20 @@ class Arr[T](n: Int) extends Mutable:
239239
An example of a `Stateful` and `Unscoped` capability that is _not_ `Separate` would be a
240240
facade class that reveals some part of an underlying `Mutable` capability.
241241

242+
## Arrays
243+
244+
The class `scala.Array` is considered a `Mutable` class if [separation checking](./separation-checking.md) is enabled. In that context, class Array can be considered to be declared roughly as follows:
245+
```scala
246+
class Array[T] extends Mutable:
247+
def length: Int
248+
def apply(i: Int): T
249+
update def update(i: Int, x: T): Unit
250+
```
251+
In fact, for technical reasons `Array` cannot extend `Mutable` or any other new traits beyond what is supported by the JVM. But for the purposes of capture and separation checking, it is still a considered a `Mutable` class.
252+
253+
By contrast, none of the mutable collections in the Scala standard library extend currently `Stateful` or `Mutable`. So to experiment with mutable collections, an
254+
alternative class library has to be used.
255+
242256
## Read-only Capabilities
243257

244258
If `x` is an exclusive capability of a type extending `Stateful`, `x.rd` is its associated _read-only_ capability.
@@ -388,7 +402,9 @@ ro.set(22) // disallowed, since `ro` is read-only access
388402

389403
## Untracked Vars
390404

391-
Sometimes, disallowing assignments to mutable fields from normal methods is too restrictive. For instance:
405+
Under [separation checking](./separation-checking.md), mutable fields are allowed to be declared only in `Stateful` classes. Updates to these fields can then only happen in update methods of these classes.
406+
407+
But sometimes, disallowing assignments to mutable fields from normal methods is too restrictive. For instance:
392408
```scala
393409
import caps.unsafe.untrackedCaptures
394410

@@ -401,17 +417,12 @@ class Cache[T](eval: () -> T):
401417
known = true
402418
x
403419
```
404-
Note that, even though `Cache` has mutable variables, it is not declared as a `Stateful` class. In this case, the mutable field `x` is used to store the result of a pure function `eval` and field `known` reflects whether `eval` was called. This is equivalent to just calling `eval()` directly but can be more efficient since the cached value is evaluated at most once. So from a semantic standpoint, it should not be necessary to make `force` an update method, even though it does assign to `x`.
420+
Note that `Cache` is not declared as a `Stateful` class, even though it has mutable fields. In this case, the mutable field `x` is used to store the result of a pure function `eval` and field `known` reflects whether `eval` was called. This is equivalent to just calling `eval()` directly but can be more efficient since the cached value is evaluated at most once. So from a semantic standpoint, it should not be necessary to make `Cache` a `Stateful` class with `force` as an update method, even though `force` does assign to `x`.
405421

406-
We can avoid the need for update methods by annotating mutable fields with `@untrackedCaptures`. Assignments to untracked mutable field are then not checked for read-only restrictions. The `@untrackedCaptures` annotation can be imported from the `scala.caps.unsafe` object. It is up to the developer
422+
We can avoid the need for stateful classes and update methods by annotating mutable fields with `@untrackedCaptures`. Assignments to untracked mutable fields are then not checked for read-only restrictions. The `@untrackedCaptures` annotation can be imported from the `scala.caps.unsafe` object. It is up to the developer
407423
to use `@untrackedCaptures` responsibly so that it does not hide visible side effects on mutable state.
408424

409-
Note that at the moment an assignment to a variable is restricted _only_ if the variable is a field of a `Stateful` class. Fields of other classes and local variables are currently not checked. So the `Cache` class above would in fact
410-
currently compile without the addition of `@untrackedCaptures`.
411-
412-
But is planned to tighten the rules in the future so that mutable fields that are not annotated with `@untrackedCaptures` can be declared only in classes extending `Stateful`. This means that all assignments to mutable fields would be checked with the read-only restriction, and `@untrackedCapture`s would become essential as an escape hatch.
413-
414-
By contrast, it is not planned to check assignments to local mutable variables, which are not fields of some class. So `@untrackedCaptures` is disallowed for such local variables.
425+
Note that the are no restrictions on assignments to local mutable variables, which are not fields of some class. So `@untrackedCaptures` is disallowed for such local variables.
415426

416427
The `untrackedCaptures` annotation can also be used in some other contexts unrelated to mutable variables. These are described in its [doc comment](https://www.scala-lang.org/api/current/scala/caps/unsafe$$untrackedCaptures.html).
417428

library/src/scala/caps/package.scala

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -203,14 +203,14 @@ def freeze(@internal.consume x: Mutable | Array[?]): x.type = x
203203

204204
@experimental
205205
object unsafe:
206-
/** Two usages:
206+
/** Three usages:
207207
*
208208
* 1. Marks the constructor parameter as untracked.
209209
* The capture set of this parameter will not be included in
210210
* the capture set of the constructed object.
211211
*
212-
* 2. Marks a class field that has a cap in its capture set, so that
213-
* the cap is not contributed to the class instance.
212+
* 2. Marks a class field that has a root capability in its capture set, so
213+
* that the root capability is not contributed to the class instance.
214214
* Example:
215215
*
216216
* class A { val b B^ = ... }; new A()
@@ -221,6 +221,9 @@ object unsafe:
221221
*
222222
* has type A. The `b` field does not contribute its cap.
223223
*
224+
* 3. Allows a field to be declarewd in a class that does not extend Stateful,
225+
* and suppresses checks for updates to the field.
226+
*
224227
* @note This should go into annotations. For now it is here, so that we
225228
* can experiment with it quickly between minor releases
226229
*/

0 commit comments

Comments
 (0)