a curated list of database news from authoritative sources

November 12, 2018

Vitess Weekly Digest - Nov 12 2018

We continue the digest from the Slack discussions for Sep 22 2018 to Oct 5 2018. We've fallen slightly behind on this, but will catch up again soon. Enable VtGateExecute in vtctld # Arsalan [Sep 22nd] Hi, I want to query vitess on vtgate but I have below error. How can i fix this problem? vitess@vtctldv3-hrl74:/$ vtctlclient -server 10.5.61.20:16999 VtGateExecute -server 10.5.61.21:16991 "show tables" E0923 05:14:55.169771 1102 main.go:61] Remote error: rpc error: code = Unknown desc = query commands are disabled (set the -enable_queries flag to enable)

November 09, 2018

October 20, 2018

On NYC, Tokyo and Seoul

I’ve lived in NYC for the past year — moved here after years in Philly and after growing up in a rural community a few hours west of there. My wife is South Korean and last week concluded my second trip to the suburbs of Seoul to visit her family. We finished up that trip with a week in Tokyo.

Long a mecha and Godzilla fan, I was struck by a city not significantly more modern, or significantly more “Eastern”, than NYC. In contrast, the lesser known Seoul is more modern than both cities and shares as much “Eastern” vibe as Tokyo.

I’d go so far as to say that Seoul is the most livable of the three for anyone of a similar background. There are a few concrete areas that led me to this including transportation, apartments, WiFi/cafes, food, and language.

I'll conclude with a few tourist recommendations and a list of books to read on South Korea and Japan if you share my enthusiasm for comparing life in different cities.

Transportation

NYC is one of the few cities in the world with a subway that runs 24/7. Tokyo and Seoul do not share this trait despite being many decades newer. (Tokyo and Seoul were heavily damaged during World War II and the Korean War, respectively.) And despite being built later, Tokyo subway cars are even less wide than NYC subway cars (~8.2ft vs. ~8.5ft).

In contrast, Seoul subway cars are ~10.2ft wide. The difference may seem slight but it is noticeable during rush hour when in Seoul there is space for four people to stand in the aisle versus room for perhaps two in a Tokyo or NYC subway car.

Seoul subway car, source: Travel Blog

The Seoul subway system is also the most advanced in terms of safety. All stations have a floor-to-ceiling barrier with doors that only open when a train arrives. Most stations in Tokyo have a ~3ft tall barrier that does the same, though some stations have no barrier. In NYC there are no barriers anywhere.

Concerning innovation, Seoul and Tokyo both have multiple driverless subway lines whereas NYC has none. But in terms of complexity the NYC subway is the simplest because you pay only once. Seoul and Tokyo subways are slightly more complex in that you swipe your card when you enter and exit (or transfer).

Taxis

It was jarring to be greeted by the very 90s, vaguely British Toyota Crown taxi cabs that dominate the streets of Tokyo.

Source: Phil Eaton

These cabs have no integrated navigation unit but a modern unit was typically mechanically attached. We saw a few of the recently approved Toyota JPN Taxi, but they only account for around 10 percent of cabs. (The integrated navigation is massive, perhaps 10-inch screens.) In contrast, Seoul has a variety of modern cabs all with integrated navigation — the most common of which is the Hyundai Sonata.

Source: The Seoul Guide

Although Japanese car companies pioneered integrated navigation in the 90s, it appears to have been the standard for South Korean car companies for the past 10-20 years.

And then there’s NYC with its primary mix of Crown Victorias and Priuses with multiple 4-inch smartphones mechanically attached for navigation.

Source: New York Post

Living

South Korea has no concept of the suburb oriented around single-family houses. Drive an hour or two out from Seoul or Busan and see the same massive, modern apartment complexes that are found in the city center. After that it's the stark farms of Kansas. Japan appears more like the US in that the city graduates steadily to suburb and farm.

Apartments in Seoul, source: Japan Times

In general, buildings in South Korea are fairly homogeneous. Even the downtown areas of Seoul have little architectural creativity. Tokyo and NYC are both diverse in building styles and sizes. However, NYC takes the cake for ubiquity of massive towers. In fact, the first time my South Korean father-in-law visited Manhattan he was blown away by this mass.

New York City, source: Wikipedia

The most popular neighborhoods in Tokyo seem more developed than their Seoul counterparts, the mass of stores and crowds extends further. And while the average age of buildings in Tokyo seems younger than the average age of buildings throughout Seoul (including less desirable areas), the developed areas (including buildings and streets) of Seoul are significantly cleaner and more modern. In contrast, and on average, Tokyo buildings seem as old as NYC buildings.

Tokyo, source: Fodors

Air quality

Air quality in NYC and Tokyo is high, pollution is low. But in recent times, air quality in Seoul has deteriorated with dangerous levels of fine dust from factories in South Korea and China. It is not clear when or how the South Korean government will address this.

WiFi/Cafes

My idea of a good cafe is a decent ratio of seats to traffic, available electrical outlets, and decent WiFi. NYC and Tokyo have some similarities: chain coffee shops are larger and non-chains are often pretty small. Tokyo differs from NYC in that there are few electrical outlets and in the existence of interior smoking sections. (Tokyo bans smoking while walking but designates areas like parks or inner rooms in restaurants or cafes.)

But the WiFi in Tokyo is abysmal. Many cafes do not have it (though the trend is to provide) and even the chains that do provide it have terrible speeds reaching peaks of 5Mbps down. In NYC WiFi is available near ~20Mbps down at most chains and ~5Mpbs at smaller non-chains.

In contrast, South Korea is the jewel of cafe culture. Unlike how in the US coffee shop size decreases as population increases, coffee shop sizes in South Korea are oddly enormous everywhere. South Korea is rich with local shops, domestic chains (including the exported Paris Baguette and Tous Les Jours), and foreign chains (South Korea has the highest number of Starbucks Reserve stores per capita of any country).

Starbucks Reserve in Seoul, source: Pulse News

From Jeju Island to Seoul we never worried about a seat or an outlet at a cafe. Furthermore, the WiFi in South Korea is incredible. My tech-hopeless in-law’s basic internet plan got 80Mbps down and the small cafes near their apartment got at least 40Mbps down.

NYC falls closer to Seoul in terms of ubiquity and speed of WiFi and has the added benefit of fast city-provided, outdoor WiFi surprisingly fast and available throughout the city. NYC is much worse in terms of daylight. Most cafes close between 8-10pm whereas cafes in Seoul and Tokyo easily stay open past 11pm.

Caveat

It’s not exactly fair to exclude internet cafes, prevalent in both Seoul and Tokyo (oddly even NYC has a few). At an internet cafe in Tokyo you can expect abundant outlets and excellent WiFi (I saw peaks of 40Mbps down). I did not visit an internet cafe in Seoul but I expect it to be similar. In both Seoul and Tokyo you can easily find 24/7 service (with showers!?).

I did not include internet cafes above because I find them slightly less convenient for tourists. Though credit is due: unlike American Chinatown internet cafes, the ones we visited in Tokyo were very clean, spacious and warm.

Internet cafe in Shinjuku, source: Rakutama

Food

Dining out in NYC is similar in cost to other major US cities. The quality is usually pretty good. Tokyo was about as expensive as food in NYC and generally as high quality. For instance, most dinners in NYC and Tokyo cost about $40-60 for two people. In contrast, most entrees in Seoul are sold for two and the dinner in total was often about $20-40. Restaurants on average seemed to be lower quality in Seoul compared to Tokyo and New York, but there are still more than enough high quality options.

Language

I am biased having a better knowledge of Korean than Japanese and a South Korean partner to fall back on. But I believe South Korea is the more friendly place for an English speaker in that it is more dedicated to providing English translations and that the written language is simpler. In both cities the penetration of English-speaking natives (and quality of speech and comprehension) is indistinguishable and decent.

To the first point, even the oddest locations and obscure signage had English translations in South Korea (not just Seoul) — not so even within Tokyo.

To the second point, Japanese has three writing systems (kanji, hiragana, and katakana). Kanji (characters originating from Chinese) cannot be replaced in writing by phonetic counterparts in hiragana or katakana. So you have little choice but to memorize all important characters, disregarding the fact that many characters can be broken down. Then you must also memorize the alphabetic systems of hiragana and katakana.

In contrast, Korean has two writing systems (hangul and hanja) where hanja (characters originating from Chinese) is primarily used in formal settings (government forms, academic books, etc.) and can be replaced with the phonetic equivalent in hangul.

This makes it much simpler to memorize and read Korean compared to Japanese.

Assorted recommendations

For New Yorkers, don’t stay in the recommended areas of Shinjuku/Shibuya/Roppongi unless you’re the type who’d enjoy staying around Times Square. These three areas of Tokyo are just as obnoxious albeit much safer. I also don’t recommend the Harajuku area; it is extra. There’s no real equivalent level of crazy in Seoul although Hongdae comes close.

In a future Tokyo trip I’d stick to the Meguro Station area including Ebisu and Daikanyama. They are beautiful, quiet neighborhoods with lots of restaurants and cafes beside the Meguro river. Areas along the Sumida River are also beautiful and quiet. Ginza/Tokyo Station is also a fun-but-not-obnoxious area to visit.

Ebisu, source: Homeaway

I cannot recommend the Edo-Tokyo Museum enough, it is the best city museum I've visited. Tsukiji is also a must see, reminding me how much I miss going to Reading Terminal Market each weekend in Philly.

In Seoul I’d recommend Yeonnam-Dong, Itaewon (which is much nicer than it’s made out to be), and Gwanghwamun. Mapo-Gu in general is a great region of Gangbuk as is the area below it (near Yeouido) in Gangnam.

Yeonnam-Dong, source: Phil Eaton

I recommend visiting the National Museum of Korea in Seoul as well as Hangang Park and Gyeongui Line Forest Park. The areas around the Tancheon stream flowing South to Bundang are also beautiful.

Tancheon near Bundang, source: Misadventures of an Awkward American

Conclusion

I came to Tokyo with the expectation of a highly modern city fused with Eastern culture. But it is difficult to see many ways it is ahead of NYC technically and it is very similar to NYC culturally. In some ways Tokyo even seems a little stuck in the past or just... off. Why are all vending machines [e.g. for tickets, ordering food, etc.] mechanical and not touch screens? The National Museum of Science is awfully old and ugly, the National Diet Building the same.

So on the one hand I’d like to let the next person down lightly on the excitement of Japan. It is a world-class city with great restaurants, live music and refined culture but all-in-all very similar to NYC. On the other hand I recommend Seoul for a cheaper, cleaner, more English-speaker friendly, and genuinely novel city with splashes of "Eastern" romantic elements like Tokyo.

Cherry blossoms in Seoul, source: English Spectrum

Further reading

MITI and the Japanese Miracle: The Growth of Industrial Policy, 1925-1975 is an excellent, albeit somewhat disputed introduction to the modern Japanese economy.

Asia’s Next Giant: South Korea and Late Industrialization is a similar high-quality introduction to the South Korean economy.

If you’re only familiar with US/Canadian companies or other “pure” market economies these two books are a great read on different, challenging styles of government policy, corporate structure, and life.

P.s. I’m looking for book recommendations on the last 20 years of economic/political history in Japan and South Korean and on the last 100 years of economic/political history in the US and NYC.

September 26, 2018

Why (and how) to read books

The last time I read for fun was in elementary school. Since college I knew I must read more, but I never forced myself to build the habit. Then three years ago I spent time around my brother and a coworker who were avid readers. This "peer pressure" helped me get started.

Since I started, I've seen concrete improvements in vocabulary. I find myself using words I didn't know I knew. I question my choice of words more. And I understand coworkers a little better. Perhaps it is only personal style, but I've also become more aware of hyperbole in my speech and have begun to tone that down.

Specifically, books provide more density of information than I can pull together myself. I've also benefited heavily from reading books on tools I use daily. Contrary to being boring, a book on a topic with which I'm familiar has been a (often needed) break from books on topics with which I am unfamiliar. The former category might include books on CSS, Bash, Emacs, Python, Scheme, data modeling, Linux/FreeBSD system administration, mystery novels, and so on. The latter category might include books on Common Lisp, system architecture, the implementation of Linux/FreeBSD, behavioral psychology, management, stock/bond markets, the history of Argentina/Chile/South Korea/Japan, sci-fi novels, and so on.

Reading diversely exposes how little I know. And that can be depressing. But I'm fairly confident reading books is the fastest way to grow.

Tactically speaking, I started slowly with few books and the ones easiest for me to read. The first year I read two books, both technical. The second year I read nine books and was able to start branching out beyond technical books. Last year I read a much more diverse set of forty books. And this year I followed suit with forty-one so far (on track for fifty-five or so).

I keep track of books I'm reading and books I want to read in Goodreads. I particularly enjoy their reading challenge system that lets you know if you are on track to meet your reading goal for the year.

September 24, 2018

Vitess Weekly Digest - Sep 24 2018

This week, we continue the digest from the Slack discussions for Sep 1 2018 to Sep 21 2018. As of this post, we are fully caught up on our backlog. Tracking progress of resharding # jk [Sep 5th] In the SplitClone Stage of resharding, how can i get the percent of process ? Or Could I estimate the time left ? sougou I don't know of a formal way, but you can look at the database size.

September 10, 2018

Vitess Weekly Digest - Sep 10 2018

This week, we continue the digest from the Slack discussions for Aug 3 2018 to Aug 31 2018. Secondary Vindexes # raj.veerappan [Aug 3 9:27 AM] how do secondary vindexes work? would they result in further sharding? weitzman [9:32 AM] If you have an authors table and a books table and you shard by author ID, a secondary vindex is a performance tool to help respond to the query, select * from books where book_id = :id

September 02, 2018

Compiling dynamic programming languages

It can be difficult to disassociate the idea that dynamically typed programming languages are tied to byte-code interpreters (e.g. YARV Ruby, CPython, V8, Zend Engine, etc.). But for many languages, a compiled implementation also exists. Cython, Chicken Scheme and SBCL are good examples.

In this post I will briefly describe how I built a compiler for my Scheme implementation using artifacts from the interpreter. In doing this, I learned a simple (not novel) technique for compiling dynamic languages. I'll introduce the Javascript to C++/V8 compiler I am developing using this technique.

BSDScheme

For the past year I've developed a Scheme implementation, BSDScheme. I started with an AST-interpreter (as opposed to a byte-code compiler and VM). A more detailed blog post on the first few steps writing BSDScheme can be found here.

As I built up support for the various objects and operations in the language, I had a sizeable base of D code for the BSDScheme runtime. This included an object representation for primitive types (and support for converting to and from types in D) as well as basic Scheme operations (+, -, car, cdr, etc.).

When the time came to implement a compiler backend, I only needed to do codegen since the parser already existed. Furthermore, the fundamental bits had already been written: object representation and much of the standard library. So I wrote the simplest compiler I could think of by targeting D and the objects/functions I had already written to support the interpreter.

Take, for example, the equals function in the standard library:

Value equals(Value arguments, void** rest) {
  auto tuple = valueToList(arguments);
  auto left = tuple[0];
  auto right = car(tuple[1]);

  bool b;

  switch (tagOfValue(left)) {
  case ValueTag.Integer:
    b = valueIsInteger(right) && valueToInteger(left) == valueToInteger(right);
    break;
  case ValueTag.Char:
    b = valueIsChar(right) && valueToChar(left) == valueToChar(right);
    break;
  case ValueTag.String:
    b = valueIsString(right) && valueToString(left) == valueToString(right);
    break;
  case ValueTag.Symbol:
    b = valueIsSymbol(right) && valueToSymbol(left) == valueToSymbol(right);
    break;
  case ValueTag.Function:
    b = valueIsFunction(right) && valueToFunction(left)[1] == valueToFunction(right)[1];
    break;
  case ValueTag.Bool:
    b = valueIsBool(right) && valueToBool(left) == valueToBool(right);
    break;
  default:
    b = false;
  }

  return makeBoolValue(b);
}

So long as my compiler generated code that used the Value object to represent Scheme data, I already had an equals function and large swaths of a Scheme standard library that I could share between the compiler and interpreter.

Ultimately I only needed to implement a few control structures to support compiling a large subset of what I supported in the interpreter. The key aspects here include: function definitions (in D), function calls (D function calls), if/else (if/else in D) and so on.

To give a concrete example of a whole program compiled, this Scheme program:

(define (exp base pow)
  (if (= pow 0)
      1
      (* base (exp base (- pow 1)))))

(define (main)
  (display (exp 2 16))
(newline))

when run through the BSDScheme compiler would become:

import std.stdio;
import lex;
import common;
import parse;
import utility;
import value;
import buffer;

Value exp(Value arguments, void** ctx) {
    Value[] tmp = listToVector(arguments);
    Value base = tmp[0];
    Value pow = tmp[1];

    Value equals_result = equals(vectorToList([pow, makeIntegerValue(0)]), null);
    Value if_result;
    if (truthy(equals_result)) {
    makeIntegerValue(1);
    if_result = makeIntegerValue(1);
    } else {

    Value minus_result = minus(vectorToList([pow, makeIntegerValue(1)]), null);

    Value exp_result = exp(vectorToList([base, minus_result]), null);

    Value times_result = times(vectorToList([base, exp_result]), null);
    if_result = times_result;
    };
    return if_result;
}

Value BSDScheme_main(Value arguments, void** ctx) {

    Value exp_result = exp(vectorToList([makeIntegerValue(2), makeIntegerValue(16)]), null);

    Value display_result = display(vectorToList([exp_result]), null);

    Value newline_result = newline(vectorToList([]), null);
    return newline_result;
}

void main() { BSDScheme_main(nilValue, cast(void**)0); }

Where every imported function had already been written for the interpreter. I had only to translate a few lines to D and import/call these existing libraries. Now I had a small binary of compiled Scheme.

It was at this point I realized I was using the same technique used by Cython to compile Python code.

...the Cython project has approached this problem by means of a source code compiler that translates Python code to equivalent C code. This code is executed within the CPython runtime environment, but at the speed of compiled C and with the ability to call directly into C libraries. http://docs.cython.org/en/latest/src/quickstart/overview.html

jsc

I played with many PL-research-y languages over the years and wanted to do build something a little more practical. So I took what I learned writing the BSDScheme compiler and decided to write a Javascript compiler. Specifically, it would target the easiest backend I could imagine: C++ using the V8 C++ library and generating a Node addon.

There already existed well-trodden guides/means of writing Node addons in C++ so I spent some time trying to hand-compile simple Javascript programs to C++ and V8. A string in Javascript would become a v8::String type in C++. A number in Javascript would become v8::Number in C++ and so forth.

I decided to write this compiler in Rust given its roots in (and my familiarity with) ML and Python. I found a Javascript parser by Dave Herman and after a few lazy weeks finally got a "Hello world!" program compiling. Getting my first program to compile has by far been the hardest part of building jsc.

Let's look at a concrete example of a recursive fibonacci program (example/recursion.js in the repo):

function fib(i) {
  if (i <= 1) {
    return i;
  }
  return fib(i - 1) + fib(i - 2);
}

function main() {
  console.log(fib(20));
}

Let's add a call to main() at the end and time this with Node to get a baseline:

$ time node example/recursion.js
6765
node example/recursion.js  0.06s user 0.02s system 97% cpu 0.083 total

Now let's install jsc to compare. We'll need Rust, Cargo, Node and Node-GYP.

$ git clone https:/github.com/eatonphil/jsc
$ cd jsc
$ make && make install
$ jsc example/recursion.js

jsc produces a Javascript entrypoint that imports our addon (build/recursion.js):

require("./build/Release/recursion").jsc_main();

And it produces a C++ file that represents the entire program (build/recursion.cc):

#include <string>

#include <node.h>

using v8::Boolean;
using v8::Context;
using v8::Exception;
using v8::Function;
using v8::FunctionTemplate;
using v8::FunctionCallbackInfo;
using v8::Isolate;
using v8::Local;
using v8::Null;
using v8::Number;
using v8::Object;
using v8::String;
using v8::False;
using v8::True;
using v8::Value;

void fib(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
  Local<Value> i = args[0];
tail_recurse_1:
  Local<Context> ctx_2 = isolate->GetCurrentContext();
  Local<Object> global_3 = ctx_2->Global();
  Local<Function> Boolean_4 = Local<Function>::Cast(global_3->Get(String::NewFromUtf8(isolate, "Boolean")));
  String::Utf8Value utf8value_tmp_5(i);
  std::string string_tmp_6(*utf8value_tmp_5);
  String::Utf8Value utf8value_tmp_7(Number::New(isolate, 1));
  std::string string_tmp_8(*utf8value_tmp_7);
  Local<Value> argv_9[] = { (i->IsNumber() || Number::New(isolate, 1)->IsNumber()) ? Boolean::New(isolate, i->ToNumber(isolate)->Value() <= Number::New(isolate, 1)->ToNumber(isolate)->Value()) : ((i->IsString() || Number::New(isolate, 1)->IsString()) ? Boolean::New(isolate, string_tmp_6 <= string_tmp_8) : (False(isolate))) };
  Local<Value> result_10 = Boolean_4->Call(Null(isolate), 1, argv_9);
  if (result_10->ToBoolean()->Value()) {
    args.GetReturnValue().Set(i);
    return;
    return;
  }
  Local<Value> arg_11 = (i->IsNumber() || Number::New(isolate, 1)->IsNumber()) ? (Number::New(isolate, i->ToNumber(isolate)->Value() - Number::New(isolate, 1)->ToNumber(isolate)->Value())) : Local<Number>::Cast(Null(isolate));
  Local<FunctionTemplate> ftpl_13 = FunctionTemplate::New(isolate, fib);
  Local<Function> fn_12 = ftpl_13->GetFunction();
  fn_12->SetName(String::NewFromUtf8(isolate, "fib"));
  Local<Value> argv_14[] = { arg_11 };
  Local<Value> result_15 = fn_12->Call(Null(isolate), 1, argv_14);
  Local<Value> arg_16 = (i->IsNumber() || Number::New(isolate, 2)->IsNumber()) ? (Number::New(isolate, i->ToNumber(isolate)->Value() - Number::New(isolate, 2)->ToNumber(isolate)->Value())) : Local<Number>::Cast(Null(isolate));
  Local<FunctionTemplate> ftpl_18 = FunctionTemplate::New(isolate, fib);
  Local<Function> fn_17 = ftpl_18->GetFunction();
  fn_17->SetName(String::NewFromUtf8(isolate, "fib"));
  Local<Value> argv_19[] = { arg_16 };
  Local<Value> result_20 = fn_17->Call(Null(isolate), 1, argv_19);
  args.GetReturnValue().Set((result_15->IsString() || result_20->IsString()) ? Local<Value>::Cast(String::Concat(result_15->ToString(), result_20->ToString())) : Local<Value>::Cast((result_15->IsNumber() || result_20->IsNumber()) ? (Number::New(isolate, result_15->ToNumber(isolate)->Value() + result_20->ToNumber(isolate)->Value())) : Local<Number>::Cast(Null(isolate))));
  return;
}

void jsc_main(const FunctionCallbackInfo<Value>& args) {
  Isolate* isolate = args.GetIsolate();
tail_recurse_21:
  Local<Value> arg_22 = Number::New(isolate, 20);
  Local<FunctionTemplate> ftpl_24 = FunctionTemplate::New(isolate, fib);
  Local<Function> fn_23 = ftpl_24->GetFunction();
  fn_23->SetName(String::NewFromUtf8(isolate, "fib"));
  Local<Value> argv_25[] = { arg_22 };
  Local<Value> result_26 = fn_23->Call(Null(isolate), 1, argv_25);
  Local<Value> arg_27 = result_26;
  Local<Function> fn_28 = Local<Function>::Cast(Local<Object>::Cast(isolate->GetCurrentContext()->Global()->Get(String::NewFromUtf8(isolate, "console")))->Get(String::NewFromUtf8(isolate, "log")));
  Local<Value> argv_29[] = { arg_27 };
  Local<Value> result_30 = fn_28->Call(Null(isolate), 1, argv_29);
  result_30;
}

void Init(Local<Object> exports) {
  NODE_SET_METHOD(exports, "jsc_main", jsc_main);
}

NODE_MODULE(NODE_GYP_MODULE_NAME, Init)

Let's time this version:

$ time node build/recursion.js
6765
node build/recursion.js  0.16s user 0.03s system 107% cpu 0.175 total

jsc, over twice as slow, is already falling behind Node. :)

As I incremented the number passed to my fibonacci function the compiled program time to completion get exponentially worse. Node stayed the same. I decided to try tail-call optimization to decrease the performance distance between Node and jsc.

I implemented tail-call optimization for the interpreter in BSDScheme by putting all functions in a loop that would break if tail-call elimination was not to happen. It took me a week to implement this and I never put it in place for the compiler. This time around I was able to add basic tail call elimination to jsc in two hours. It is done by labels and gotos instead of a tail call when applicable.

Here is a tail-call optimized version of the same program (example/tco.js):

function fib(n, a, b) {
    if (n == 0) {
        return a;
    }

    if (n == 1) {
        return b;
    }

    return fib(n - 1, b, a + b);
}

function main() {
  console.log(fib(50, 0, 1));
}

We add a call to main() again for Node and time it:

$ time node example/tco.js
12586269025
node example/tco.js  0.06s user 0.02s system 96% cpu 0.080 total

And compile it with jsc and time it:

$ jsc example/tco.js
$ time node build/tco.js
12586269025
node build/tco.js  0.07s user 0.02s system 95% cpu 0.087 total

Well that's not bad at all. :)

Next steps with jsc

jsc has very limited support for... everything. Today I added almost all primitive numeric operations + equality/inequality operations + unit tests. jsc does not yet support nested functions, callbacks, or closures. It supports while loops but not yet for loops. And I'm not sure if it supports else if. It does not support arrays or objects let alone constructors and prototypes. Adding support for these is low-hanging fruit.

After the low-hanging fruit, more interesting projects for jsc include:

  • generating C++ with embedded V8 rather than only targeting Node addons
  • type inference or type hinting for generating unboxed functions a la Cython and SBCL