Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.
Typed Channels                              and                           Macros                           Dr. Roland Kuhn...
The Problem                  someActor ! CommandOnesöndag 10 februari 13
The Problem                  trait Command                  case class CommandOne(param: String) extends Command          ...
The Vision                           someActor <-!- CommandOne(”msg”)                        because the other does not co...
But How?                        • ActorRef must know about message types                          – Actor type must be par...
And the replies?                            val f: Future[Response] =                        someActor <-?- CommandOne(”he...
And How This?                        • ActorRef must know reply types                          – Actor must be parameteriz...
No Type Pollution                        • Generic Filter/Transform Actors                          – accept management co...
Actors Do Compose                         msg -?-> firstActor -?-> secondActor -!-> client                        msg -?->...
The Result:söndag 10 februari 13
Type-Safe Composability                             of                        Actor Systemssöndag 10 februari 13
Relation to π-calculus                        • Actors are composite processes                        • Actor types are st...
That was the                            Eloi world                        Now we’re going to visit the Morlockssöndag 10 f...
The Implementation                        • Tagged type union with                          :+:[(In, Out), ChannelList] <:...
How to Declare it?                  class OpinionatedEcho extends Actor                      with Channels[TNil, (String, ...
First Problem: Lambdas                        • Type-checker transforms lambda before the                          macro c...
First Problem: Lambdas                        private class Behaviorist[-R, Ch: ru.TypeTag](                            wr...
The Gory Details                        def impl[LUB, ReplyChannels <: ChannelList,                            MsgTChan <:...
The Gory Details                        trait Channels[P <: ChannelList, C <: ChannelList] {                          this...
Sample Type Calculation                    final def missingChannels(u: Universe)(                        channels: u.Type...
How to Return a Type                        def impl[..., ReplyChannels <: ChannelList, ...]                            (c...
Sharing Code with Runtime                        final def x(u: Universe)(list: u.Type, msg: u.Type)                      ...
How to test it?                        def mkToolbox(compileOptions: String = "")                          : ToolBox[_ <: ...
How to test it?                    intercept[ToolBoxError] {                        eval("""                             i...
get it and learn more                           http://akka.io                        http://letitcrash.com               ...
E0Fsöndag 10 februari 13
Upcoming SlideShare
Loading in …5
×

Akka typed-channels

2,488 views

Published on

These slides are for my presentation at North-East Scala Symposium 2013 in Philadelphia, see http://nescala.org. The video is available at http://www.youtube.com/watch?v=PCk2SHufw3E

Published in: Education
  • Be the first to comment

Akka typed-channels

  1. 1. Typed Channels and Macros Dr. Roland Kuhn @rolandkuhnsöndag 10 februari 13
  2. 2. The Problem someActor ! CommandOnesöndag 10 februari 13
  3. 3. The Problem trait Command case class CommandOne(param: String) extends Command someActor ! CommandOnesöndag 10 februari 13
  4. 4. The Vision someActor <-!- CommandOne(”msg”) because the other does not compilesöndag 10 februari 13
  5. 5. But How? • ActorRef must know about message types – Actor type must be parameterized • Message type is verified against thatsöndag 10 februari 13
  6. 6. And the replies? val f: Future[Response] = someActor <-?- CommandOne(”hello”) because the compiler knowssöndag 10 februari 13
  7. 7. And How This? • ActorRef must know reply types – Actor must be parameterized with them • Reply types are extracted at call sitesöndag 10 februari 13
  8. 8. No Type Pollution • Generic Filter/Transform Actors – accept management commands – pass on generic other type • Using just one type is not enough! • Need to use type unions and allow multiple possible reply types for one inputsöndag 10 februari 13
  9. 9. Actors Do Compose msg -?-> firstActor -?-> secondActor -!-> client msg -?-> someService -*-> (_ map httpOk) -!-> client Process wiring from the outsidesöndag 10 februari 13
  10. 10. The Result:söndag 10 februari 13
  11. 11. Type-Safe Composability of Actor Systemssöndag 10 februari 13
  12. 12. Relation to π-calculus • Actors are composite processes • Actor types are structural, not nominal • wiring A͡B can be done situationally http://doc.akka.io/ see Typed Channelssöndag 10 februari 13
  13. 13. That was the Eloi world Now we’re going to visit the Morlockssöndag 10 februari 13
  14. 14. The Implementation • Tagged type union with :+:[(In, Out), ChannelList] <: ChannelList • Value class ChannelRef[…](val a: ActorRef) • Actor mixin Channels[…] • WrappedMessage[…, LUB](val m: LUB) • ops desugar to tell/ask after type checksöndag 10 februari 13
  15. 15. How to Declare it? class OpinionatedEcho extends Actor with Channels[TNil, (String, String) :+: TNil] { channel[String] { (str, sender) ⇒ sender <-!- str } // or channel[String] { case (”hello”, sender) ⇒ sender <-!- ”world” case (x, sender) ⇒ sender <-!- s”dunno: $x” } } “sender” will accept only String messagessöndag 10 februari 13
  16. 16. First Problem: Lambdas • Type-checker transforms lambda before the macro call – pattern matches or PartialFunction literals generate checks depending on static type info • Behavior is not an argument to “channels” • macro only emits object with right “apply”söndag 10 februari 13
  17. 17. First Problem: Lambdas private class Behaviorist[-R, Ch: ru.TypeTag]( wrapped: Boolean) extends (R ⇒ Unit) { // ... def apply(recv: R): Unit = { val tt = ru.typeTag[Ch] behavior ++= ( for (t ← inputChannels(ru)(tt.tpe)) yield tt.mirror.runtimeClass(t.widen) -> ff(recv)) } } calling channels[_] registers the behaviorsöndag 10 februari 13
  18. 18. The Gory Details def impl[LUB, ReplyChannels <: ChannelList, MsgTChan <: ChannelList, MsgT: c.WeakTypeTag, MyCh <: ChannelList: c.WeakTypeTag, ParentCh <: ChannelList: c.WeakTypeTag]( c: Context { type PrefixType = Channels[ParentCh, MyCh] }): c.Expr[(Nothing ⇒ Unit)] = { // some type calculations happen here val prepTree = reify(...) reify { prepTree.splice c.prefix.splice.behaviorist[ (MsgT, ChannelRef[ReplyChannels]) ⇒ Unit, MsgT]( bool(c, false).splice)(universe.typeTag[MsgT]) } }söndag 10 februari 13
  19. 19. The Gory Details trait Channels[P <: ChannelList, C <: ChannelList] { this: Actor ⇒ def channel[T]: (Nothing ⇒ Unit) = macro macros.Channel.impl[Any, ChannelList, ChannelList, T, C, P] def behaviorist[R, Ch: ru.TypeTag](wrapped: Boolean) : (R ⇒ Unit) = new Behaviorist[R, Ch](wrapped) // ... }söndag 10 februari 13
  20. 20. Sample Type Calculation final def missingChannels(u: Universe)( channels: u.Type, required: List[u.Type]): List[u.Type] = { import u._ // making the top-level method recursive blows up the compiler def rec(ch: Type, req: List[Type]): List[Type] = { ch match { case TypeRef(_, _, TypeRef(_, _, in :: _) :: tail :: Nil) ⇒ rec(tail, req filterNot (_ <:< in)) case last ⇒ req filterNot (_ <:< last) } } rec(channels, required) }söndag 10 februari 13
  21. 21. How to Return a Type def impl[..., ReplyChannels <: ChannelList, ...] (c: Context): c.Expr[(Nothing ⇒ Unit)] = { // calculate “channels: u.Type” and then: implicit val ttReplyChannels = c.TypeTag[ReplyChannels](channels) reify { ...[(..., ...[ReplyChannels]) ⇒ ..., ...]... } } “reify” picks up TypeTags and uses their .tpesöndag 10 februari 13
  22. 22. Sharing Code with Runtime final def x(u: Universe)(list: u.Type, msg: u.Type) : List[u.Type] = { val imp = u.mkImporter(ru) val tpeReplyChannels = imp.importType(ru.typeOf[ReplyChannels[_]]) val tpeTNil = imp.importType(ru.typeOf[TNil]) // ... } otherwise there will be weird exceptionssöndag 10 februari 13
  23. 23. How to test it? def mkToolbox(compileOptions: String = "") : ToolBox[_ <: scala.reflect.api.Universe] = { val m = scala.reflect.runtime.currentMirror m.mkToolBox(options = compileOptions) } def eval(code: String, compileOptions: String = "-cp akka-actor/target/classes:akka-channels/target/classes") : Any = { val tb = mkToolbox(compileOptions) tb.eval(tb.parse(code)) }söndag 10 februari 13
  24. 24. How to test it? intercept[ToolBoxError] { eval(""" import akka.channels._ import ChannelSpec._ implicit val c = new ChannelRef[TNil](null) new ChannelRef[(A, C) :+: TNil](null) <-!- B """) }.message must include( "target ChannelRef does not support messages of " + "types akka.channels.ChannelSpec.B.type")söndag 10 februari 13
  25. 25. get it and learn more http://akka.io http://letitcrash.com http://typesafe.comsöndag 10 februari 13
  26. 26. E0Fsöndag 10 februari 13

×