Attenuation

This is an example of attenuation in ocaps.

Attenuation is used to “narrow” a capability, by limiting the accessible functionality. It is the dual of Composition.

You can read Managing Capabilities in the guide for more information.

import ocaps.macros._

object Attenuation {

  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 {
      def doer(foo: Foo): Doer = foo.capabilities.doer
      def changer(foo: Foo): Changer = foo.capabilities.changer
    }
  }

  def main(args: Array[String]): Unit = {
    import Foo._

    val access = new 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)

    // We want an attenuation that makes only Doer available
    val castDoer: Doer = doerChangerDerper.asInstanceOf[Doer]
    // But we can recover Derper capability here!
    val doerAsDerper: Derper = castDoer.asInstanceOf[Derper]
    // whoops :-(
    doerAsDerper.derp()

    // Attenuation doesn't use downcasting, is safe!
    val attenuatedDoer: Doer = attenuate[Doer](doerChangerDerper)
    try {
      val downcastAttenuatedDerper = attenuatedDoer.asInstanceOf[Derper]
      attenuatedDoer.doTheThing()
    } catch {
      case e: ClassCastException =>
        println("Can't downcast to a different type using the macro!")
    }
  }
}
Full source at GitHub