Last active
August 29, 2015 14:16
-
-
Save IainHull/dcde1207d4a8f6d0f942 to your computer and use it in GitHub Desktop.
Improve your correctness with Types - Scala Days SF 2015
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Order(orderId: String, | |
customerId: String, | |
items: Vector[OrderItem], | |
amount: MoneyAmount, | |
submittedAt: DateTime) | |
case class Customer(name: String, | |
preferredCurrency: Currency) | |
class MoneyAmount(val amount: BigDecimal) extends AnyVal { | |
def + (rhs: MoneyAmount): MoneyAmount = | |
new MoneyAmount(amount + rhs.amount) | |
def - (rhs: MoneyAmount): MoneyAmount = | |
new MoneyAmount(amount - rhs.amount) | |
def * (rhs: Rate): MoneyAmount = | |
new MoneyAmount(amount * rhs.size) | |
} | |
class Rate(val size: BigDecimal) extends AnyVal { | |
def * (rhs: Rate): MoneyAmount = rhs * this | |
} | |
def creditCardRate4(customer: Customer): Rate = { | |
if (customer.preferredCurrency === Currency.USD) | |
new Rate(BigDecimal("0.015")) | |
else | |
new Rate(BigDecimal("0.025")) | |
} | |
object Test { | |
val order: Order = ??? | |
val customer: Customer = ??? | |
// Now rates can only multiply amounts | |
val creditCardCharge = order.amount * creditCardRate4(customer) | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
case class Customer(name: String, | |
preferredCurrency: String) { | |
require(Currency.isValid(preferredCurrency)) | |
} | |
case class Customer(name: String, | |
preferredCurrency: String) { | |
require(Currency.isValid(preferredCurrency)) | |
} | |
val customer = Customer(name = "Joe Bloggs", | |
preferredCurrency = "SFO") |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Currency private (val code: String) extends AnyVal | |
object Currency { | |
val USD: Currency = new Currency("USD") | |
val EUR: Currency = new Currency("EUR") | |
// ... | |
def from(code: String): Option[Currency] = ??? | |
} |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
trait EntryDescriptionLike { | |
def name: Name | |
def owner: User | |
} | |
trait EntryLike { | |
def data: InputStream | |
} | |
trait Storage { | |
type Entry <: EntryLike | |
type EntryDescription <: EntryDescriptionLike | |
def create(name: Name, owner: User): EntryDescription | |
def find(name: Name): Option[EntryDescription] | |
def read(entryDescription: EntryDescription): Entry | |
} | |
class StorageImpl extends Storage { | |
type Entry = EntryImpl | |
type EntryDescription = EntryDescriptionImpl | |
private[StorageImpl] case class EntryImpl(val data: InputStream) extends EntryLike | |
private[StorageImpl] case class EntryDescriptionImpl(id: Long, name: Name, owner: User) extends EntryDescriptionLike | |
def create(name: Name, owner: User): EntryDescription = ??? | |
def find(name: Name): Option[EntryDescription] = ??? | |
def read(entryDescription: EntryDescription): Entry = { | |
dataStore.read(entryDescription.id) | |
} | |
} | |
scala> val riakStorage1 = new RiakStorage | |
riakStorage1: RiakStorage = RiakStorage@3605ce8f | |
scala> val memoryStorage = new MemoryStorage | |
memoryStorage: MemoryStorage = MemoryStorage@680aef16 | |
scala> val riakStorage2 = new RiakStorage | |
riakStorage2: RiakStorage = RiakStorage@70c14473 | |
scala> val desc = riakStorage1.create(name, user) | |
desc: riakStorage1.EntryDescription = EntryDescriptionImpl(1,Some Path,aUser) | |
scala> memoryStorage.find(desc) | |
<console>:22: error: type mismatch; | |
found : riakStorage1.EntryDescription | |
(which expands to) riakStorage1.EntryDescriptionImpl | |
required: Name | |
memoryStorage.find(desc) | |
^ | |
scala> riakStorage2.find(desc) | |
<console>:21: error: type mismatch; | |
found : riakStorage1.EntryDescription | |
(which expands to) riakStorage1.EntryDescriptionImpl | |
required: Name | |
riakStorage2.find(desc) |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment