You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
`opaque` is a [soft modifier](../soft-modifier.html). It can still be used as a normal identifier when it is not in front of a definition keyword.
13
+
14
+
Opaque type aliases must be members of classes, traits, or objects, or they are defined
15
+
at the top-level. They cannot be defined in local blocks.
16
+
17
+
### Type Checking
18
+
19
+
The general form of a (monomorphic) opaque type alias is
20
+
```scala
21
+
opaquetypeT>:L<:U=R
22
+
```
23
+
where the lower bound `L` and the upper bound `U` may be missing, in which case they are assumed to be `scala.Nothing` and `scala.Any`, respectively. If bounds are given, it is checked that the right hand side `R` conforms to them, i.e. `L <: R` and `R <: U`.
24
+
25
+
Inside the scope of the alias definition, the alias is transparent: `T` is treated
26
+
as a normal alias of `R`. Outside its scope, the alias is treated as the abstract type
27
+
```scala
28
+
typeT>:L<:U`
29
+
```
30
+
A special case arises if the opaque type is defined in an object. Example:
31
+
```
32
+
object o {
33
+
opaque type T = R
34
+
}
35
+
```
36
+
In this case we have inside the object (also for non-opaque types) that `o.T` is equal to
37
+
`T` or its expanded form `o.this.T`. Equality is understood here as mutual subtyping, i.e.
38
+
`o.T <: o.this.T` and `o.this.T <: T`. Furthermore, we have by the rules of opaque types
39
+
that `o.this.T` equals `R`. The two equalities compose. That is, inside `o`, it is
40
+
also known that `o.T` is equal to `R`. This means the following code type-checks:
41
+
```scala
42
+
objecto {
43
+
opaquetypeT=Int
44
+
valx:Int= id(2)
45
+
}
46
+
defid(x: o.T): o.T= x
47
+
```
48
+
49
+
### Relationship to SIP 35
50
+
51
+
Opaque types in Dotty are an evolution from what is described in
Copy file name to clipboardExpand all lines: docs/docs/reference/other-new-features/opaques.md
+71-21Lines changed: 71 additions & 21 deletions
Original file line number
Diff line number
Diff line change
@@ -6,39 +6,42 @@ title: "Opaque Type Aliases"
6
6
Opaque types aliases provide type abstraction without any overhead. Example:
7
7
8
8
```scala
9
-
opaquetypeLogarithm=Double
10
-
```
11
-
12
-
This introduces `Logarithm` as a new type, which is implemented as `Double` but is different from it. The fact that `Logarithm` is the same as `Double` is only known in the companion object of `Logarithm`. Here is a possible companion object:
9
+
objectLogarithms {
13
10
14
-
```scala
15
-
objectLogarithm {
11
+
opaquetypeLogarithm=Double
16
12
17
-
// These are the ways to lift to the logarithm type
18
-
defapply(d: Double):Logarithm= math.log(d)
13
+
objectLogarithm {
19
14
20
-
defsafe(d: Double):Option[Logarithm] =
21
-
if (d >0.0) Some(math.log(d)) elseNone
15
+
// These are the ways to lift to the logarithm type
16
+
defapply(d: Double):Logarithm=math.log(d)
22
17
23
-
// This is the first way to unlift the logarithm type
24
-
defexponent(l: Logarithm):Double= l
18
+
defsafe(d: Double):Option[Logarithm] =
19
+
if (d >0.0) Some(math.log(d)) elseNone
20
+
}
25
21
26
22
// Extension methods define opaque types' public APIs
The companion object contains with the `apply` and `safe` methods ways to convert from doubles to `Logarithm` values. It also adds an `exponent` function and a decorator that implements `+` and `*` on logarithm values, as well as a conversion `toDouble`. All this is possible because within object `Logarithm`, the type `Logarithm` is just an alias of `Double`.
31
+
This introduces `Logarithm` as a new type, which is implemented as `Double` but is different from it. The fact that `Logarithm` is the same as `Double` is only known in the scope where
32
+
`Logarithm` is defined which in this case is object `Logarithms`.
33
+
34
+
The public API of `Logarithm` consists of the `apply` and `safe` methods that convert from doubles to `Logarithm` values, an extension method `toDouble` that converts the other way,
35
+
and operations `+` and `*` on logarithm values. The implementations of these functions
36
+
type-check because within object `Logarithms`, the type `Logarithm` is just an alias of `Double`.
37
37
38
-
Outside the companion object, `Logarithm` is treated as a new abstract type. So the
38
+
Outside its scope, `Logarithm` is treated as a new abstract type. So the
39
39
following operations would be valid because they use functionality implemented in the `Logarithm` object.
40
40
41
41
```scala
42
+
importLogarithms._
43
+
importPredef.{any2stringadd=>_, _}
44
+
42
45
vall=Logarithm(1.0)
43
46
vall2=Logarithm(2.0)
44
47
vall3= l * l2
@@ -54,6 +57,53 @@ But the following operations would lead to type errors:
54
57
l / l2 // error: `/` is not a member fo Logarithm
55
58
```
56
59
57
-
`opaque` is a [soft modifier](../soft-modifier.html).
60
+
Aside: the `any2stringadd => _` import suppression is necessary since otherwise the universal `+` operation in `Predef` would take precedence over the `+` extension method in `LogarithmOps`. We plan to resolve this wart by eliminating `any2stringadd`.
61
+
62
+
### Bounds For Opaque Type Aliases
63
+
64
+
Opaque type aliases can also come with bounds. Example:
0 commit comments