Dynamic Sealing

import ocaps._

// Brands allow for "flexible private fields" where
// you have lexical scoping or in situations where
// access modifiers are not suitable (i.e. there is not
// a containing class)
object DynamicSeal {

  trait Message

  case object Save extends Message

  case object Kill extends Message

  trait Decision

  case object Saved extends Decision

  case object Killed extends Decision

  // All of the users are of the same type, and so private fields
  // are no good here.  In addition, the boxed field is public
  // so anyone who is asking and who has the unsealer can see it.
  case class User(
    name: String,
    sentencer: User => User = identity,
    boxed: Option[Brand.Box[Message]] = None,
    private val brand: Option[Brand[Message]] = None
  ) {
    def sentence(user: User): User = sentencer(user)

    def process(user: User): Option[Message] = {
      for {
        box <- user.boxed
        brand <- brand
        message <- brand.unapply(box)
      } yield message

  def main(args: Array[String]): Unit = {
    val softBrand = Brand.create[Message]("Brand for Judge Softtouch")
    val doomBrand = Brand.create[Message]("Brand for Judge Doom")

    val judgeSofttouch = User("Judge Softtouch", sentencer = { user =>
      user.copy(boxed = Some(softBrand(Save)))
    }, brand = Some(softBrand))

    val judgeDoom = User("Judge Doom", sentencer = { user =>
      user.copy(boxed = Some(doomBrand(Kill)))
    }, brand = Some(doomBrand))

    val steve = judgeDoom.sentence(User("steve"))
    val will = judgeSofttouch.sentence(User("will"))
    val judgedDoom = judgeSofttouch.sentence(judgeDoom)

    val steveDecision = judgeDoom.process(steve)
      s"User ${steve.name} has message ${steve.boxed} and decision $steveDecision"
    val willDecision = judgeSofttouch.process(will)
      s"User ${will.name} has message ${will.boxed} and decision $willDecision"

    // What's going on here...
    val judgeDecision = judgedDoom.process(judgedDoom)
      s"User ${judgedDoom.name} has message ${judgedDoom.boxed} and decision $judgeDecision"

Full source at GitHub