Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- import scala.language.existentials
- class KeyShape {}
- abstract class Key {
- def ref(): KeyShape
- }
- abstract class Lock[T] {
- type Corresponding <: Key
- def ref: KeyShape
- def unlock(key: Corresponding): T
- def tryUnlock(key: Key): Option[T] = {
- if (key.ref == this.ref)
- Some(unlock(key.asInstanceOf[Corresponding]))
- else
- None
- }
- }
- class LockAndKey[T] {
- private val _ref = new KeyShape
- final class MatchingKey() extends Key {
- def ref = _ref
- }
- class MatchingLock(private val inner: T) extends Lock[T] {
- type Corresponding = MatchingKey
- def ref = _ref
- def unlock(key: Corresponding): T = {
- if (key == null) // For security reasons, check and make sure null hasn't slipped in
- throw new NullPointerException
- inner
- }
- }
- def producePair(inner: T): (MatchingKey, MatchingLock) = (new MatchingKey, new MatchingLock(inner))
- }
- object LockAndKey extends App {
- // Each lock hides an object which can only be accessed using the corresponding key.
- val(key1, lock1) = (new LockAndKey).producePair(7)
- val(key2, lock2) = (new LockAndKey).producePair("ABC")
- val(key3, lock3) = (new LockAndKey).producePair(10)
- // If the type system can prove that the key and lock match, you don't have to go through an Option[T]
- println(lock1.unlock(key1))
- println(lock2.unlock(key2))
- println(lock3.unlock(key3))
- // This line does not even compile, since the lock and key don't line up
- // println(lock1.unlock(key3))
- // Attempting to pass null is illegal
- // println(lock3.unlock(null))
- // If the type system isn't certain, you can use tryUnlock, which returns an Option[T]
- println(lock1.tryUnlock(key1)) // Matching, so okay
- println(lock2.tryUnlock(key1)) // Returns None
- // This one will typecheck but will crash at runtime since the types don't line up.
- // println(lock3.tryUnlock(new Key { override def ref() = lock3.ref; }));
- // We can't force the types to line up using anonymous subclasses either, since MatchingKey
- // is declared to be final.
- // val breaker = new LockAndKey
- // println(lock3.tryUnlock(new breaker.MatchingKey { override def ref() = lock3.ref; }))
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement