Skip to content

Instantly share code, notes, and snippets.

@IainHull
Last active August 29, 2015 14:17
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save IainHull/accbc45f52f8241a98de to your computer and use it in GitHub Desktop.
Save IainHull/accbc45f52f8241a98de to your computer and use it in GitHub Desktop.
PathDependentTypes
package org.iainhull.types
/**
* Created by iain.hull on 17/03/2015.
*/
package pdt {
import java.io.OutputStream
import scala.util.Try
case class Name(name: String)
case class User(user: String)
trait DataStore {
def read(id: Long): Try[OutputStream]
}
package after {
trait Handle {
def name: Name
def owner: User
}
trait Data {
def stream: OutputStream
}
trait Storage {
def create(name: Name, owner: User,
data: OutputStream): Handle
def find(name: Name): Option[Handle]
def read(handle: Handle): Try[Data]
}
case class HandleImpl(id: Long,
name: Name,
owner: User) extends Handle
case class DataImpl(stream: OutputStream) extends Data
class StorageImpl extends Storage {
// ... 
def read(entryDesc: Handle): Try[Data] = {
require(entryDesc.isInstanceOf[HandleImpl])
val impl = entryDesc.asInstanceOf[HandleImpl]
dataStore.read(impl.id) map { stream => DataImpl(stream)}
}
val dataStore: DataStore = ???
}
object Example {
val riakStorage: Storage = ???
val memoryStorage: Storage = ???
val someName = Name("foo")
val maybeData1 = for {
handle <- riakStorage.find(someName)
data <- riakStorage.read(handle).toOption
} yield data
// This is a bug
val maybeData2 = for {
handle <- riakStorage.find(someName)
data <- memoryStorage.read(handle).toOption
} yield data
}
}
package after {
trait HandleLike {
def name: Name
def owner: User
}
trait DataLike {
def stream: OutputStream
}
trait Storage2 {
type Handle <: HandleLike
type Data <: DataLike
def create(name: Name, owner: User,
data: OutputStream): Handle
def find(name: Name): Option[Handle]
def read(handle: Handle): Try[Data]
}
package impl {
private[impl] class StorageImpl extends Storage2 {
type Handle = HandleImpl
type Data = DataImpl
case class HandleImpl(id: Long,
name: Name,
owner: User) extends HandleLike
case class DataImpl(stream: OutputStream) extends DataLike
// ... 
def read(entryDesc: Handle): Try[Data] = {
dataStore.read(entryDesc.id) map { stream => DataImpl(stream)}
}
val dataStore: DataStore = ???
}
}
object Example2 {
val riakStorage: Storage2 = ???
val memoryStorage: Storage2 = ???
val someName = Name("foo")
val maybeData1 = for {
handle <- riakStorage.find(someName)
data <- riakStorage.read(handle).toOption
} yield data
// This is a bug
val maybeData2 = for {
handle <- riakStorage.find(someName)
data <- memoryStorage.read(handle).toOption
} yield data
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment