Skip to content

Instantly share code, notes, and snippets.

@dwijnand
Created December 6, 2018 07:03
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 dwijnand/b09a134c03bc087fdc6d7627b93c46e5 to your computer and use it in GitHub Desktop.
Save dwijnand/b09a134c03bc087fdc6d7627b93c46e5 to your computer and use it in GitHub Desktop.
Playing with typesafe builder patterns
object RefOrNull {
type Id[A >: Null <: AnyRef] = A
type No[A >: Null <: AnyRef] = Null
def nullAs[A] = null.asInstanceOf[A]
def sideEffect[A](result: A, exprs: Any*): A = result
def set[A, B](result: A, exprs: Any*): B = result.asInstanceOf[B]
}
import RefOrNull._
final class Data[
S[SP >: Null <: AnyRef] <: SP,
W[WP >: Null <: AnyRef] <: WP,
D[DP >: Null <: AnyRef] <: DP,
] private (
val id: String,
private[Data] var _schedule: Int,
private[Data] var _warehouse: String,
private[Data] var _delivered: Int,
) {
def schedule: Int = _schedule
def warehouse[A >: Null <: AnyRef](implicit ev: W[A] =:= Id[A]): String = _warehouse
}
object Data {
type InitT = Data[No, No, No]
type ScheduledT = Data[Id, No, No]
type WarehouseAssignedT = Data[Id, Id, No]
type DeliveredT = Data[Id, Id, Id]
def create(id: String): InitT = new InitT(id, nullAs, nullAs, nullAs)
implicit class Schedulable(private val data: InitT) extends AnyVal {
def schedule_=(schedule: Int): ScheduledT = new ScheduledT(data.id, schedule, nullAs, nullAs)
}
implicit class WarehouseAssignable(private val data: ScheduledT) extends AnyVal {
def warehouse_=(warehouse: String): WarehouseAssignedT =
set[WarehouseAssignedT](data, data._warehouse = warehouse)
}
implicit class Deliverable(private val data: WarehouseAssignedT) extends AnyVal {
def delivered_=(deliveryNum: Int): DeliveredT =
new DeliveredT(data.id, data.schedule, data.warehouse, deliveryNum)
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment