Amplification

Amplification is when two object references put together result in an ability to do something not possible if you don’t have references to both.

Technically, the Access pattern qualifies:

sourceobject Document {
  trait NameChanger {
    def changeName(name: String): Unit
  }
}
object Document {
  trait NameChanger {
    def changeName(name: String): Unit
  }

  class Access {
    def nameChanger(doc: Document): NameChanger = {
      doc.capabilities.nameChanger
    }
  }
}

But amplification is more about bringing together independent objects. The canonical example is a can and can opener, brought together by dynamic sealing:

sourceimport ocaps._

object Amplification {

  case class Food(name: String)

  case class Can(food: Brand.Box[Food])

  class CanOpener(unsealer: Brand.Unsealer) {
    def open(can: Can): Food = {
      unsealer(can.food).get
    }
  }

  def main(args: Array[String]): Unit = {
    // We want to get at the food here.

    val (sealer, unsealer) = Brand.create("canned food").tuple
    val canOfSpam: Can = Can(sealer(Food("spam")))

    // The can by itself has the food, but we have no way to get to it
    val cannedFood: Brand.Box[Food] = canOfSpam.food
    println(s"food = ${cannedFood.toString}") // DOES NOT WORK

    // The can opener by itself can open cans, but if we don't have a can
    // then there's also no food.
    val canOpener = new CanOpener(unsealer)

    // We need both Can and CanOpener.
    def openCan(can: Can, canOpener: CanOpener) = {
      val food: Food = canOpener.open(can) // DOES WORK

      println(s"food = $food")
    }

    openCan(canOfSpam, canOpener)
  }
}
The source code for this page can be found here.