Commit b06ff395 authored by Kenton Varda's avatar Kenton Varda

More doc updates, blog post.

parent 425657bb
safe: true safe: true
permalink: /news/:year-:month-:day-:title.html permalink: /news/:year-:month-:day-:title.html
baseurl: /capnproto/ baseurl: /capnproto/
is_next: false
safe: true
permalink: /news/:year-:month-:day-:title.html
baseurl: /capnproto/next/
is_next: true
...@@ -27,6 +27,15 @@ ...@@ -27,6 +27,15 @@
<a id="forkme_banner" href="https://github.com/kentonv/capnproto">View on GitHub</a> <a id="forkme_banner" href="https://github.com/kentonv/capnproto">View on GitHub</a>
</div> </div>
{% if site.is_next %}
<div id="next_banner">
<h1>PREVIEW</h1>
<p>You are looking at the site as it will appear after the next release. This is a draft
version that may be incomplete, buggy, or not yet applicable. To look at the current
site, <a href="../">click here</a>.
</div>
{% endif %}
<!-- MAIN CONTENT --> <!-- MAIN CONTENT -->
<div id="main_content_wrap" class="outer"> <div id="main_content_wrap" class="outer">
......
...@@ -17,7 +17,7 @@ href="https://groups.google.com/group/capnproto-announce">Stay Updated</a></div> ...@@ -17,7 +17,7 @@ href="https://groups.google.com/group/capnproto-announce">Stay Updated</a></div>
{{ content }} {{ content }}
<script type="text/javascript">setupNewsSidebar([ <script type="text/javascript">setupNewsSidebar([
{% for post in site.posts %} {% for post in site.posts %}
{ title: "{{ post.title }}", url: "/capnproto{{ post.url }}" }, { title: "{{ post.title }}", url: "{{ site.baseurl }}.{{ post.url }}" },
{% endfor %} {% endfor %}
]);</script> ]);</script>
{% include footer.html %} {% include footer.html %}
---
layout: post
title: "Cap'n Proto v0.4: Time Traveling RPC"
author: kentonv
---
Well, Hofstadter kicked in and this release took way too long. But, after three long months, I'm
happy to announce...
### Time-Traveling RPC
<img src='{{ site.baseurl }}images/time-travel.png' style='max-width:639px'>
v0.4 finally introduces the long-promised [RPC system]({{ site.baseurl }}rpc.html). Traditionally,
RPC is plagued by the fact that networks have latency, and pretending that latency doesn't exist by
hiding hiding it behind what looks like a normal function call only makes the problem worse.
Cap'n Proto has a simple solution to this problem: send call results _back in time_, so they
arrive at the client at the point in time when the call was originally made!
Curious how Cap'n Proto bypasses the laws of physics?
[Check out the docs!]({{ site.baseurl }}rpc.html)
### Promises in C++
If you do any Javascript programming, you've probably heard of
[Promises/A+](http://promisesaplus.com/) and similar proposals. Cap'n Proto RPC introduces a
similar construct in C++. In fact, the API is nearly identical, and its semantics are nearly
identical. Compare with
[Domenic Denicola's Javascript example](http://domenic.me/2012/10/14/youre-missing-the-point-of-promises/):
{% highlight c++ %}
// C++ version of Domenic's Javascript promises example.
getTweetsFor("domenic") // returns a promise
.then([](vector<Tweet> tweets) {
auto shortUrls = parseTweetsForUrls(tweets);
auto mostRecentShortUrl = shortUrls[0];
// expandUrlUsingTwitterApi returns a promise
return expandUrlUsingTwitterApi(mostRecentShortUrl);
})
.then(httpGet) // promise-returning function
.then(
[](string responseBody) {
cout << "Most recent link text:" << responseBody << endl;
},
[](kj::Exception&& error) {
cerr << "Error with the twitterverse:" << error << endl;
}
);
{% endhighlight %}
This is C++, but it is no more lines than the equivalent Javascript. We're doing several I/O
operations, we're doing them asynchronously, and we don't have a huge unreadable mess of callback
functions. Promises are based on event loop concurrency, which means you can perform concurrent
operations with shared state without worrying about mutex locking -- i.e., the Javascript model.
(Of course, if you really want threads, you can run multiple event loops in multiple threads.)
[More on C++ promises.]({{ site.baseurl }}cxxrpc.html#kj_concurrency_framework)
### Up Next
Cap'n Proto is far from done, but working on it in a bubble will not produce ideal results.
Starting after the holidays, I will be refocusing some of my time into an adjacent project which
will be a heavy user of Cap'n Proto. I hope this experience will help me experience first hand
the pain points in the current interface and keep development going in the right direction.
This does, however, mean that core Cap'n Proto development will slow somewhat (unless contributors
pick up the slack! ;) ). I am extremely excited about this next project, though, and I think you
will be too. Stay tuned!
...@@ -75,7 +75,7 @@ kj::Promise<kj::String> contentPromise = ...@@ -75,7 +75,7 @@ kj::Promise<kj::String> contentPromise =
fetchHttp("http://example.com"); fetchHttp("http://example.com");
kj::Promise<int> lineCountPromise = kj::Promise<int> lineCountPromise =
promise.then([](kj::String& content) { promise.then([](kj::String&& content) {
return countChars(content, '\n'); return countChars(content, '\n');
}); });
{% endhighlight %} {% endhighlight %}
...@@ -98,7 +98,7 @@ block. ...@@ -98,7 +98,7 @@ block.
{% highlight c++ %} {% highlight c++ %}
kj::Promise<int> lineCountPromise = kj::Promise<int> lineCountPromise =
promise.then([](kj::String& content) { promise.then([](kj::String&& content) {
return countChars(content, '\n'); return countChars(content, '\n');
}, [](kj::Exception&& exception) { }, [](kj::Exception&& exception) {
// Error! Pretend the document was empty. // Error! Pretend the document was empty.
...@@ -152,7 +152,7 @@ called when the promise either completes or is canceled. ...@@ -152,7 +152,7 @@ called when the promise either completes or is canceled.
### Other Features ### Other Features
KJ promise a number of primitive operations that can be performed on promises. The complete API KJ supports a number of primitive operations that can be performed on promises. The complete API
is documented directly in the `kj/async.h` header. Additionally, see the `kj/async-io.h` header is documented directly in the `kj/async.h` header. Additionally, see the `kj/async-io.h` header
for APIs for performing basic network I/O -- although Cap'n Proto RPC users typically won't need for APIs for performing basic network I/O -- although Cap'n Proto RPC users typically won't need
to use these APIs directly. to use these APIs directly.
......
...@@ -140,8 +140,7 @@ that value to mean "not present". ...@@ -140,8 +140,7 @@ that value to mean "not present".
Pointer fields are a bit different. They start out "null", and you can check for nullness using Pointer fields are a bit different. They start out "null", and you can check for nullness using
the `hasFoo()` accessor. You could use a null pointer to mean "not present". Note, though, that the `hasFoo()` accessor. You could use a null pointer to mean "not present". Note, though, that
calling `getFoo()` on a null pointer returns the default value, which is indistinguishable from a calling `getFoo()` on a null pointer returns the default value, which is indistinguishable from a
legitimate value. The receiver of the message therefore needs to explicitly check `hasFoo()` legitimate value, so checking `hasFoo()` is in fact the _only_ way to detect nullness.
before calling the getter.
### How do I resize a list? ### How do I resize a list?
......
function initSidebar() { function initSidebar() {
var filename = document.location.pathname.slice("/capnproto".length); var filename = document.location.pathname.slice("/capnproto".length);
if (filename.slice(0, 5) == "/next") {
filename = filename.slice(5);
}
if (filename == "/") { if (filename == "/") {
filename = "/index.html"; filename = "/index.html";
} else if (filename.slice(0, 6) == "/news/") { } else if (filename.slice(0, 6) == "/news/") {
......
...@@ -10,7 +10,7 @@ href="https://groups.google.com/group/capnproto-announce">Stay Updated</a></div> ...@@ -10,7 +10,7 @@ href="https://groups.google.com/group/capnproto-announce">Stay Updated</a></div>
<h1>News</h1> <h1>News</h1>
{% for post in site.posts %} {% for post in site.posts %}
<h2><a href="/capnproto{{ post.url }}">{{ post.title }}</a></h2> <h2><a href="{{ site.baseurl }}.{{ post.url }}">{{ post.title }}</a></h2>
<p class="author"> <p class="author">
<a href="https://github.com/{{ post.author }}">{{ post.author }}</a> <a href="https://github.com/{{ post.author }}">{{ post.author }}</a>
{% if post.author == 'kentonv' %} {% if post.author == 'kentonv' %}
......
#! /bin/bash #! /bin/bash
set -eu set -eu
shopt -s extglob
if [ "x$(git status --porcelain)" != "x" ]; then if [ "x$(git status --porcelain)" != "x" ]; then
echo "error: git repo has uncommited changes." >&2 echo -n "git repo has uncommited changes. Continue anyway? (y/N) " >&2
exit 1 read -n 1 YESNO
echo >&2
if [ "x$YESNO" != xy ]; then
exit 1
fi
fi fi
case $(git rev-parse --abbrev-ref HEAD) in
master )
echo "On master branch. Will generate to /next."
CONFIG=_config_next.yml
PREFIX=/next
LABEL="preview site"
;;
release-* )
echo "On release branch. Will generate to /."
CONFIG=_config.yml
PREFIX=
LABEL="site"
;;
* )
echo "Unrecognized branch." >&2
exit 1
;;
esac
echo "Checking out doc branch in ./.gh-pages..." echo "Checking out doc branch in ./.gh-pages..."
if [ ! -e .gh-pages ]; then if [ ! -e .gh-pages ]; then
git clone -b gh-pages https://github.com/kentonv/capnproto.git .gh-pages git clone -b gh-pages git@github.com:kentonv/capnproto.git .gh-pages
cd .gh-pages cd .gh-pages
else else
cd .gh-pages cd .gh-pages
...@@ -26,16 +52,17 @@ cd .. ...@@ -26,16 +52,17 @@ cd ..
echo "Regenerating site..." echo "Regenerating site..."
rm -rf _site .gh-pages/* rm -rf _site .gh-pages$PREFIX/!(next)
jekyll build --safe jekyll build --safe --config $CONFIG
cp -r _site/* .gh-pages mkdir -p .gh-pages$PREFIX
cp -r _site/* .gh-pages$PREFIX
REV="$(git rev-parse HEAD)" REV="$(git rev-parse HEAD)"
cd .gh-pages cd .gh-pages
git add * git add *
git commit -m "site generated @$REV" git commit -m "$LABEL generated @$REV"
if [ "x$(git status --porcelain)" != "x" ]; then if [ "x$(git status --porcelain)" != "x" ]; then
echo "error: .gh-pages is not clean after commit." >&2 echo "error: .gh-pages is not clean after commit." >&2
...@@ -46,7 +73,7 @@ echo -n "Push now? (y/N)" ...@@ -46,7 +73,7 @@ echo -n "Push now? (y/N)"
read -n 1 YESNO read -n 1 YESNO
echo echo
if [ "$YESNO" == "y" ]; then if [ "x$YESNO" == "xy" ]; then
git push git push
cd .. cd ..
else else
......
...@@ -45,8 +45,8 @@ OK, fair enough. In a traditional RPC system, we might solve our problem by int ...@@ -45,8 +45,8 @@ OK, fair enough. In a traditional RPC system, we might solve our problem by int
method `foobar()` which combines `foo()` and `bar()`. Now we've eliminated the round trip, without method `foobar()` which combines `foo()` and `bar()`. Now we've eliminated the round trip, without
inventing a new protocol. inventing a new protocol.
The problem is, this kind of arbitrary combining of orthogonal features quickly turns nice, elegant The problem is, this kind of arbitrary combining of orthogonal features quickly turns elegant
object-oriented protocols into ad-hoc procedural messes. object-oriented protocols into ad-hoc messes.
For example, consider the following interface: For example, consider the following interface:
...@@ -81,7 +81,7 @@ interface File { ...@@ -81,7 +81,7 @@ interface File {
} }
{% endhighlight %} {% endhighlight %}
This a very clean interface for interacting with a file system. But say you are using this This is a very clean interface for interacting with a file system. But say you are using this
interface over a satellite link with 1000ms latency. Now you have a problem: simply reading the interface over a satellite link with 1000ms latency. Now you have a problem: simply reading the
file `foo` in directory `bar` takes four round trips! file `foo` in directory `bar` takes four round trips!
...@@ -102,7 +102,7 @@ So now you're going to change it. You'll probably do something like: ...@@ -102,7 +102,7 @@ So now you're going to change it. You'll probably do something like:
call takes a path as an argument. call takes a path as an argument.
{% highlight capnp %} {% highlight capnp %}
# A sad, singleton-y interface. # A sad, singleton-ish interface.
interface Filesystem { interface Filesystem {
list @0 (path :Text) -> (list :List(Text)); list @0 (path :Text) -> (list :List(Text));
...@@ -176,10 +176,10 @@ for others to access the capability without consent of either the host or the re ...@@ -176,10 +176,10 @@ for others to access the capability without consent of either the host or the re
the host only assigns it an ID specific to the connection over which it was sent. the host only assigns it an ID specific to the connection over which it was sent.
Capability-based design patterns -- which largely boil down to object-oriented design patterns -- Capability-based design patterns -- which largely boil down to object-oriented design patterns --
work great with Cap'n Proto. Such patterns tend to be much more agile than traditional ACL-based work great with Cap'n Proto. Such patterns tend to be much more adaptable than traditional
security, making it easy to keep security tight and avoid confused-deputy attacks while minimizing ACL-based security, making it easy to keep security tight and avoid confused-deputy attacks while
pain for legitimate users. That said, you can of course implement ACLs or any other pattern on top minimizing pain for legitimate users. That said, you can of course implement ACLs or any other
of capabilities. pattern on top of capabilities.
## Protocol Features ## Protocol Features
......
...@@ -380,6 +380,28 @@ body.normal #main_content.inner { ...@@ -380,6 +380,28 @@ body.normal #main_content.inner {
padding: 50px 10px 30px 10px; padding: 50px 10px 30px 10px;
} }
#next_banner {
position: absolute;
left: 100px;
right: 100px;
top: 100px;
z-index: 100;
border: 2px solid black;
background-color: rgba(196, 196, 196, 0.8);
text-align: center;
color: black;
padding: 30px;
}
#next_banner h1 {
color: black;
font-size: 750%;
}
#next_banner p {
margin: 1em 100px;
}
#project_title { #project_title {
margin: 0; margin: 0;
color: #fff; color: #fff;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment