Composition

This is an example of composition using ocaps.

Composition is fairly simple. You have two capabilities implemented as traits, A and B. Using composition, you create a proxy which has a compound type of A with B.

You can read more in Constructing Capabilities section of the guide.

sourceimport ocaps.macros._

object Composition {

  final class Foo(private var name: String) {
    private object capabilities {
      val doer: Foo.Doer = new Foo.Doer {
        override def doTheThing(): Unit = {
          println(s"$name.doTheThing()")
        }
      }
      val changer: Foo.Changer = new Foo.Changer {
        override def changeName(name: String): Foo.this.type = {
          Foo.this.name = name
          Foo.this
        }
      }
    }
  }

  object Foo {
    trait Doer {
      def doTheThing(): Unit
    }

    trait Changer {
      def changeName(name: String): Foo
    }

    trait Derper {
      def derp(): Unit
    }

    class Access private {
      def doer(foo: Foo): Doer = foo.capabilities.doer
      def changer(foo: Foo): Changer = foo.capabilities.changer
    }

    object Access {
      def apply(): Access = new Access
    }
  }

  def main(args: Array[String]): Unit = {
    import Foo._
    val access = Foo.Access()
    val foo = new Foo("foo")
    val doer: Doer = access.doer(foo)
    val changer: Changer = access.changer(foo)
    val derper: Derper = new Derper {
      override def derp(): Unit = println("derp!")
    }
    val doerChangerDerper =
      compose[Doer with Changer with Derper](doer, changer, derper)

    // composition is often used when you want to return a "set" of capabilities after
    // some authorization event has taken place, after which you can do some pattern matching
    doerChangerDerper match {
      case d: Derper =>
        d.derp()
    }

    // this of course works with all of the compound types, but you can also use attenuation
    // to pull out a particular capability.
    val attenuatedChanger: Changer = doerChangerDerper match {
      case c: Changer =>
        attenuate[Changer](c)
    }
    attenuatedChanger.changeName("bar")
  }
}
The source code for this page can be found here.