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.