官术网_书友最值得收藏!

Phantom types

The phantom type in Scala is a type that is never instantiated at runtime. Because of this, it is only useful at compile time to express domain constraints similar to (generalized) type constraints. To get a feeling for how this works, let's imagine the following situation—we have an abstraction of Lock, that has already been implemented in different ways via the use of inheritance:

sealed trait Lock
class PadLock extends Lock
class CombinationLock extends Lock

We would like to encode in the type system that only the following state transitions are allowed for any locks:

  • open -> closed
  • closed -> open
  • closed -> broken
  • open -> broken

As we already have an existing hierarchy, we cannot easily model these state transitions with inheritance by extending Lock with ClosedLock, OpenLock, and BrokenLock. Instead, we will use the phantom types Open, Closed, and Broken to model the states (we will define Lock from scratch later, just to avoid cluttering the example with unnecessary details):

sealed trait LockState
sealed trait Open extends LockState
sealed trait Closed extends LockState
sealed trait Broken extends LockState

Now, we can assign this State to a Lock:

case class Lock[State <: LockState]()

And define our state transitioning methods using type constraints:

def break: Lock[Broken] = Lock()
def
open[_ >: State <: Closed](): Lock[Open] = Lock()
def close[_ >: State <: Open](): Lock[Closed] = Lock()

We can bring any lock to the broken state so that the break method does not have any constraints defined on it.

The transition to the Open state is only available from the Closed state, and we encode this fact with the existential type (that, nevertheless, should be available for successful compilation), which is a subclass of the current State of the lock and a superclass of Closed. The only possibility to satisfy type constraint is for State to be equal to Closed. This is done in the same way that it is only possible way to call the close method and satisfy type constraints by having Lock in the Open state. Let's see how the compiler reacts in different cases:

scala> val openLock = Lock[Open]
openLock: Lock[Open] = Lock()
scala> val closedLock = openLock.close()
closedLock: Lock[Closed] = Lock()
scala> val broken = closedLock.break
broken: Lock[Broken] = Lock()
scala> closedLock.close()
^
error: inferred type arguments [Closed] do not conform to method close's type parameter bounds [_ >: Closed <: Open]
scala> openLock.open()
^
error: inferred type arguments [Open] do not conform to method open's type parameter bounds [_ >: Open <: Closed]
scala> broken.open()
^
error: inferred type arguments [Broken] do not conform to method open's type parameter bounds [_ >: Broken <: Closed]

The compiler refuses to accept calls that would lead to inappropriate state transitions. 

We can also provide an alternative implementation by using generalized type constraints:

def open(implicit ev: State =:= Closed): Lock[Open] = Lock()
def close(implicit ev: State =:= Open): Lock[Closed] = Lock()

It is arguable that the generalized syntax conveys the intention much better as it almost reads as State should be equal to Closed in the first case or State should be equal to Open in the second case.

Let's see how the compiler reacts to our new implementation:

scala> val openLock = Lock[Open]
openLock: Lock[Open] = Lock()

scala> val closedLock = openLock.close
closedLock: Lock[Closed] = Lock()

scala> val lock = closedLock.open
lock: Lock[Open] = Lock()

scala> val broken = closedLock.break
broken: Lock[Broken] = Lock()

scala> closedLock.close
^
error: Cannot prove that Closed =:= Open.

scala> openLock.open
^
error: Cannot prove that Open =:= Closed.

scala> broken.open
^
error: Cannot prove that Broken =:= Closed.

Obviously, the error messages are also better for the implementation with generalized type constraints.

主站蜘蛛池模板: 宜昌市| 元氏县| 斗六市| 平邑县| 樟树市| 岗巴县| 会同县| 洪雅县| 仲巴县| 尉氏县| 蛟河市| 阜新市| 砚山县| 惠来县| 益阳市| 大名县| 周口市| 咸丰县| 万荣县| 乐至县| 红原县| 定远县| 嘉黎县| 承德市| 砚山县| 余庆县| 拉孜县| 清远市| 万年县| 平和县| 沙河市| 射阳县| 呼伦贝尔市| 尼木县| 阜宁县| 沙坪坝区| 汾阳市| 临高县| 瓦房店市| 五华县| 叙永县|