Skip to content

Commit 86e3c53

Browse files
authored
Merge pull request #8440 from panacekcz/explain-opaque-example
Clarify example in opaque type documentation
2 parents d2d04f6 + 52927eb commit 86e3c53

File tree

1 file changed

+31
-12
lines changed

1 file changed

+31
-12
lines changed

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

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -71,21 +71,32 @@ object Access {
7171

7272
def (x: Permissions) & (y: Permissions): Permissions = x | y
7373
def (x: PermissionChoice) | (y: PermissionChoice): PermissionChoice = x | y
74-
def (x: Permissions).is(y: Permissions) = (x & y) == y
75-
def (x: Permissions).isOneOf(y: PermissionChoice) = (x & y) != 0
74+
def (granted: Permissions).is(required: Permissions) = (granted & required) == required
75+
def (granted: Permissions).isOneOf(required: PermissionChoice) = (granted & required) != 0
7676

7777
val NoPermission: Permission = 0
78-
val ReadOnly: Permission = 1
79-
val WriteOnly: Permission = 2
80-
val ReadWrite: Permissions = ReadOnly & WriteOnly
81-
val ReadOrWrite: PermissionChoice = ReadOnly | WriteOnly
78+
val Read: Permission = 1
79+
val Write: Permission = 2
80+
val ReadWrite: Permissions = Read | Write
81+
val ReadOrWrite: PermissionChoice = Read | Write
8282
}
8383
```
8484
The `Access` object defines three opaque types:
8585

8686
- `Permission`, representing a single permission,
87-
- `Permissions`, representing a conjunction (logical "and") of permissions,
88-
- `PermissionChoice`, representing a disjunction (logical "or") of permissions.
87+
- `Permissions`, representing a set of permissions with the meaning "all of these permissions granted",
88+
- `PermissionChoice`, representing a set of permissions with the meaning "at least one of these permissions granted".
89+
90+
Outside the `Access` object, values of type `Permissions` may be combined using the `&` operator,
91+
where `x & y` means "all permissions in `x` *and* in `y` granted".
92+
Values of type `PermissionChoice` may be combined using the `|` operator,
93+
where `x | y` means "a permission in `x` *or* in `y` granted".
94+
95+
Note that inside the `Access` object, the `&` and `|` operators always resolve to the corresponding methods of `Int`,
96+
because members always take precedence over extension methods.
97+
Because of that, the `|` extension method in `Access` does not cause infinite recursion.
98+
Also, the definition of `ReadWrite` must use `|`,
99+
even though an equivalent definition outside `Access` would use `&`.
89100

90101
All three opaque types have the same underlying representation type `Int`. The
91102
`Permission` type has an upper bound `Permissions & PermissionChoice`. This makes
@@ -97,13 +108,21 @@ object User {
97108

98109
case class Item(rights: Permissions)
99110

100-
val x = Item(ReadOnly) // OK, since Permission <: Permissions
111+
val roItem = Item(Read) // OK, since Permission <: Permissions
112+
val rwItem = Item(ReadWrite)
113+
val noItem = Item(NoPermission)
114+
115+
assert( roItem.rights.is(ReadWrite) == false )
116+
assert( roItem.rights.isOneOf(ReadOrWrite) == true )
117+
118+
assert( rwItem.rights.is(ReadWrite) == true )
119+
assert( rwItem.rights.isOneOf(ReadOrWrite) == true )
101120

102-
assert( x.rights.is(ReadWrite) == false )
103-
assert( x.rights.isOneOf(ReadOrWrite) == true )
121+
assert( noItem.rights.is(ReadWrite) == false )
122+
assert( noItem.rights.isOneOf(ReadOrWrite) == false )
104123
}
105124
```
106-
On the other hand, the call `x.rights.isOneOf(ReadWrite)` would give a type error
125+
On the other hand, the call `roItem.rights.isOneOf(ReadWrite)` would give a type error
107126
since `Permissions` and `PermissionChoice` are different, unrelated types outside `Access`.
108127

109128
[More details](opaques-details.md)

0 commit comments

Comments
 (0)