cannam@147: --- cannam@147: layout: post cannam@147: title: "Cap'n Proto v0.4: Time Traveling RPC" cannam@147: author: kentonv cannam@147: --- cannam@147: cannam@147: Well, [Hofstadter](http://en.wikipedia.org/wiki/Hofstadter's_law) kicked in and this release took cannam@147: way too long. But, after three long months, I'm happy to announce: cannam@147: cannam@147: ### Time-Traveling RPC _(Promise Pipelining)_ cannam@147: cannam@147: cannam@147: cannam@147: v0.4 finally introduces the long-promised [RPC system]({{ site.baseurl }}rpc.html). Traditionally, cannam@147: RPC is plagued by the fact that networks have latency, and pretending that latency doesn't exist by cannam@147: hiding it behind what looks like a normal function call only makes the problem worse. cannam@147: Cap'n Proto has a simple solution to this problem: send call results _back in time_, so they cannam@147: arrive at the client at the point in time when the call was originally made! cannam@147: cannam@147: Curious how Cap'n Proto bypasses the laws of physics? cannam@147: [Check out the docs!]({{ site.baseurl }}rpc.html) cannam@147: cannam@147: _UPDATE: There has been some confusion about what I'm claiming. I am NOT saying that using cannam@147: promises alone (i.e. being asynchronous) constitutes "time travel". Cap'n Proto implements a cannam@147: technique called Promise Pipelining which allows a new request to be formed based on the content cannam@147: of a previous result (in part or in whole) before that previous result is returned. Notice in the cannam@147: diagram that the result of foo() is being passed to bar(). Please cannam@147: [see the docs]({{ site.baseurl }}rpc.html) or cannam@147: [check out the calculator example](https://github.com/kentonv/capnproto/blob/master/c++/samples) cannam@147: for more._ cannam@147: cannam@147: ### Promises in C++ cannam@147: cannam@147: _UPDATE: More confusion. This section is **not** about pipelining ("time travel"). This section cannam@147: is just talking about implementing a promise API in C++. Pipelining is another feature on top of cannam@147: that. Please [see the RPC page]({{ site.baseurl }}rpc.html) if you want to know more about cannam@147: pipelining._ cannam@147: cannam@147: If you do a lot of serious Javascript programming, you've probably heard of cannam@147: [Promises/A+](http://promisesaplus.com/) and similar proposals. Cap'n Proto RPC introduces a cannam@147: similar construct in C++. In fact, the API is nearly identical, and its semantics are nearly cannam@147: identical. Compare with cannam@147: [Domenic Denicola's Javascript example](http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/): cannam@147: cannam@147: {% highlight c++ %} cannam@147: // C++ version of Domenic's Javascript promises example. cannam@147: getTweetsFor("domenic") // returns a promise cannam@147: .then([](vector tweets) { cannam@147: auto shortUrls = parseTweetsForUrls(tweets); cannam@147: auto mostRecentShortUrl = shortUrls[0]; cannam@147: // expandUrlUsingTwitterApi returns a promise cannam@147: return expandUrlUsingTwitterApi(mostRecentShortUrl); cannam@147: }) cannam@147: .then(httpGet) // promise-returning function cannam@147: .then( cannam@147: [](string responseBody) { cannam@147: cout << "Most recent link text:" << responseBody << endl; cannam@147: }, cannam@147: [](kj::Exception&& error) { cannam@147: cerr << "Error with the twitterverse:" << error << endl; cannam@147: } cannam@147: ); cannam@147: {% endhighlight %} cannam@147: cannam@147: This is C++, but it is no more lines -- nor otherwise more complex -- than the equivalent cannam@147: Javascript. We're doing several I/O operations, we're doing them asynchronously, and we don't cannam@147: have a huge unreadable mess of callback functions. Promises are based on event loop concurrency, cannam@147: which means you can perform concurrent operations with shared state without worrying about mutex cannam@147: locking -- i.e., the Javascript model. (Of course, if you really want threads, you can run cannam@147: multiple event loops in multiple threads and make inter-thread RPC calls between them.) cannam@147: cannam@147: [More on C++ promises.]({{ site.baseurl }}cxxrpc.html#kj_concurrency_framework) cannam@147: cannam@147: ### Python too cannam@147: cannam@147: [Jason](https://github.com/jparyani) has been diligently keeping his cannam@147: [Python bindings](http://jparyani.github.io/pycapnp/) up to date, so you can already use RPC there cannam@147: as well. The Python interactive interpreter makes a great debugging tool for calling C++ servers. cannam@147: cannam@147: ### Up Next cannam@147: cannam@147: Cap'n Proto is far from done, but working on it in a bubble will not produce ideal results. cannam@147: Starting after the holidays, I will be refocusing some of my time into an adjacent project which cannam@147: will be a heavy user of Cap'n Proto. I hope this experience will help me discover first hand cannam@147: the pain points in the current interface and keep development going in the right direction. cannam@147: cannam@147: This does, however, mean that core Cap'n Proto development will slow somewhat (unless contributors cannam@147: pick up the slack! ;) ). I am extremely excited about this next project, though, and I think you cannam@147: will be too. Stay tuned!