@@ -49,10 +49,62 @@ methodWithUnusedEv(evidence1)
49
49
methodWithUnusedEv(unusedEvidence2)
50
50
```
51
51
52
- Examples
53
- --------
54
- TODO
52
+ State machine example
53
+ ---------------------
54
+ The following examples shows an implementation of a simple state machine which can be in a state ` On ` or ` Off ` .
55
+ The machine can change state from ` Off ` to ` On ` with ` turnedOn ` only if it is currently ` Off ` ,
56
+ conversely from ` On ` to ` Off ` with ` turnedOff ` only if it is currently ` On ` . These last constraint are
57
+ captured with the ` IsOff[S] ` and ` IsOn[S] ` implicit evidence only exist for ` IsOff[Off] ` and ` InOn[On] ` .
58
+ For example, not allowing calling ` turnedOff ` on in an ` Off ` state as we would require an evidence ` IsOn[Off] `
59
+ that will not be found.
60
+
61
+ As the implicit evidences of ` turnedOn ` and ` turnedOff ` are not used in the bodies of those functions
62
+ we can mark them as ` unused ` . This will remove the evidence parameters at runtime, but we would still
63
+ evaluate the ` isOn ` and ` isOff ` implicits that where found as arguments.
64
+ As ` isOn ` and ` isOff ` are not used except as as ` unused ` arguments, we can mark them as ` unused ` , hence
65
+ removing the evaluation of the ` isOn ` and ` isOff ` evidences.
55
66
56
67
``` scala
57
-
68
+ import scala .annotation .implicitNotFound
69
+
70
+ sealed trait State
71
+ final class On extends State
72
+ final class Off extends State
73
+
74
+ @ implicitNotFound(" State is must be Off" )
75
+ class IsOff [S <: State ]
76
+ object IsOff {
77
+ unused implicit def isOff : IsOff [Off ] = new IsOff [Off ]
78
+ }
79
+
80
+ @ implicitNotFound(" State is must be On" )
81
+ class IsOn [S <: State ]
82
+ object IsOn {
83
+ unused implicit def isOn : IsOn [On ] = new IsOn [On ]
84
+ }
85
+
86
+ class Machine [S <: State ] private {
87
+ def turnedOn (implicit unused ev : IsOff [S ]): Machine [On ] = new Machine [On ]
88
+ def turnedOff (implicit unused ev : IsOn [S ]): Machine [Off ] = new Machine [Off ]
89
+ }
90
+
91
+ object Machine {
92
+ def newMachine (): Machine [Off ] = new Machine [Off ]
93
+ }
94
+
95
+ object Test {
96
+ def main (args : Array [String ]): Unit = {
97
+ val m = Machine .newMachine()
98
+ m.turnedOn
99
+ m.turnedOn.turnedOff
100
+
101
+ // m.turnedOff
102
+ // ^
103
+ // State is must be On
104
+
105
+ // m.turnedOn.turnedOn
106
+ // ^
107
+ // State is must be Off
108
+ }
109
+ }
58
110
```
0 commit comments