Skip to content

Commit 9bbe374

Browse files
committed
Tweak Permissions example
Add an example usage and a few more words to existing explanation. Also add a few commas.
1 parent 3ca087c commit 9bbe374

File tree

1 file changed

+24
-12
lines changed

1 file changed

+24
-12
lines changed

docs/_docs/reference/other-new-features/opaques.md

+24-12
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ end MyMath
3333

3434
This introduces `Logarithm` as a new abstract type, which is implemented as `Double`.
3535
The fact that `Logarithm` is the same as `Double` is only known in the scope where
36-
`Logarithm` is defined which in the above example corresponds to the object `MyMath`.
37-
Or in other words, within the scope it is treated as type alias, but this is opaque to the outside world
38-
where in consequence `Logarithm` is seen as an abstract type and has nothing to do with `Double`.
36+
`Logarithm` is defined, which in the above example corresponds to the object `MyMath`.
37+
Or in other words, within the scope, it is treated as a type alias, but this is opaque to the outside world
38+
where, in consequence, `Logarithm` is seen as an abstract type that has nothing to do with `Double`.
3939

4040
The public API of `Logarithm` consists of the `apply` and `safe` methods defined in the companion object.
4141
They convert from `Double`s to `Logarithm` values. Moreover, an operation `toDouble` that converts the other way, and operations `+` and `*` are defined as extension methods on `Logarithm` values.
@@ -70,13 +70,12 @@ object Access:
7070
opaque type PermissionChoice = Int
7171
opaque type Permission <: Permissions & PermissionChoice = Int
7272

73-
extension (x: Permissions)
74-
def & (y: Permissions): Permissions = x | y
7573
extension (x: PermissionChoice)
7674
def | (y: PermissionChoice): PermissionChoice = x | y
75+
extension (x: Permissions)
76+
def & (y: Permissions): Permissions = x | y
7777
extension (granted: Permissions)
7878
def is(required: Permissions) = (granted & required) == required
79-
extension (granted: Permissions)
8079
def isOneOf(required: PermissionChoice) = (granted & required) != 0
8180

8281
val NoPermission: Permission = 0
@@ -101,9 +100,12 @@ where `x | y` means "a permission in `x` *or* in `y` granted".
101100

102101
Note that inside the `Access` object, the `&` and `|` operators always resolve to the corresponding methods of `Int`,
103102
because members always take precedence over extension methods.
104-
Because of that, the `|` extension method in `Access` does not cause infinite recursion.
105-
Also, the definition of `ReadWrite` must use `|`,
106-
even though an equivalent definition outside `Access` would use `&`.
103+
For that reason, the `|` extension method in `Access` does not cause infinite recursion.
104+
105+
In particular, the definition of `ReadWrite` must use `|`, the bitwise operator for `Int`,
106+
even though client code outside `Access` would use `&`, the extension method on `Permissions`.
107+
The internal representations of `ReadWrite` and `ReadOrWrite` are identical, but this is not visible to the client,
108+
which is interested only in the semantics of `Permissions`, as in the example below.
107109

108110
All three opaque type aliases have the same underlying representation type `Int`. The
109111
`Permission` type has an upper bound `Permissions & PermissionChoice`. This makes
@@ -115,8 +117,11 @@ object User:
115117
import Access.*
116118

117119
case class Item(rights: Permissions)
120+
extension (item: Item)
121+
def +(other: Item): Item = Item(item.rights & other.rights)
118122

119123
val roItem = Item(Read) // OK, since Permission <: Permissions
124+
val woItem = Item(Write)
120125
val rwItem = Item(ReadWrite)
121126
val noItem = Item(NoPermission)
122127

@@ -128,11 +133,18 @@ object User:
128133

129134
assert(!noItem.rights.is(ReadWrite))
130135
assert(!noItem.rights.isOneOf(ReadOrWrite))
136+
137+
assert((roItem + woItem).rights.is(ReadWrite))
131138
end User
132139
```
133-
134-
On the other hand, the call `roItem.rights.isOneOf(ReadWrite)` would give a type error
135-
since `Permissions` and `PermissionChoice` are different, unrelated types outside `Access`.
140+
On the other hand, the call `roItem.rights.isOneOf(ReadWrite)` would give a type error:
141+
```scala
142+
assert(roItem.rights.isOneOf(ReadWrite))
143+
^^^^^^^^^
144+
Found: (Access.ReadWrite : Access.Permissions)
145+
Required: Access.PermissionChoice
146+
```
147+
`Permissions` and `PermissionChoice` are different, unrelated types outside `Access`.
136148

137149

138150
### Opaque Type Members on Classes

0 commit comments

Comments
 (0)