@@ -49,10 +49,62 @@ methodWithUnusedEv(evidence1)
4949methodWithUnusedEv(unusedEvidence2)
5050```
5151
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.
5566
5667``` 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+ }
58110```
0 commit comments