C++ has a new standard called C++0x (Wikipedia, Bjarne Stroustrup) that includes many interesting features such as Lambda, For Each, List Initialization ... Those features are so powerful that they allow to write C++ as if it was Javascript.

The goal of this project is to transform C++ into Javascript. We want to be able to copy & paste Javascript into C++ and be able to run it. While this is not 100% feasible, the result is quite amazing.

This is only a prototype. In about 600 lines of code we manage to make the core of the Javascript language.

You can view the source and compile examples at the JSPP Github Repository.

JSON

The Javascript Object notation can be emulated thanks to C++0x initialization lists and a bit of operator overload hackery. _ has an operator [] that returns a KeyValue object, that has an operator = overload that fills both keys and values. For each value of the initialization listL If that's an objet, it is treated like an Array (add one to the lenght and use the length as key). If that's a KeyValue, both key and value are set.

There is an ambiguity with nested initialization lists, we use _() to cast the list into an Object. It is probably possible to fix it.

C++

var json = {
    _["number"] = 42,
    _["string"] = "vjeux",
    _["array"] = {1, 2, "three"},
 
    _["nested"] = _({
        _["first"] = 1
    })
};
 
std::cout < < json;
// {array: [1, 2, three], nested: {first: 1},
//  number: 42, string: vjeux}
Javascript

var json = {
    "number": 42,
    "string": "vjeux",
    "array": [1, 2, "three"],
 
    "nested": {
        "first": 1
    }
};
 
console.log(json);
// {number: 42, string: 'vjeux',
//  array: [1, 2, three], nested: {first: 1}}

Function

C++0x added lambda to the language with the following syntax: [capture] (arguments) -> returnType { body }. function is a macro that transforms function (var i) into [=] (Object This, Object arguments, var i) -> Object. This allows to use the Javascript syntax and let us sneakily add the this and arguments magic variables.

C++ is strongly typed and even lambdas have types. We can overload the Object constructor on
lambda arity and have a typed container for each one. Then, we overload the () operator that will call the stored lambda. We we carefully add undefined values for unspecified arguments and fill the This and arguments variables.

In Javascript, when a function does not return a value, it returns undefined. Sadly, we cannot have a default return value in C++, you have to write it yourself.

Since everything must be typed in C++, we have to add var before the argument name.

C++

var Utils = {
  _["map"] = function (var array, var func) {
    for (var i = 0; i < array["length"]; ++i) {
      array[i] = func(i, array[i]);
    }
    return undefined;
  }
};
 
var a = {"a", "b", "c"};
std::cout << a;
// [a, b, c]
 
Utils["map"](a, function (var key, var value) {
  return "(" + key + ":" + value + ")";
});
std::cout << a;
// [(0:a), (1:b), (2:c)]
Javascript

var Utils = {
  "map": function (array, func) {
    for (var i = 0; i < array["length"]; ++i) {
      array[i] = func(i, array[i]);
    }
 
  }
};
 
var a = ["a", "b", "c"];
console.log(a);
// [a, b, c]
 
Utils["map"](a, function (key, value) {
  return "(" + key + ":" + value + ")";
});
console.log(a);
// [(0:a), (1:b), (2:c)]

Closure

There are two ways to capture variables with lambda in C++: either by reference or by value. What we would like is to capture by reference in order for all the variables to be bound to the same object. However, when the initial variable gets out of scope it is destroyed, and any attempt to read it results in a Segmentation Fault!

Instead, we have to capture it by value. It means that a new object is created for each lambda capturing the variable. Our objects are manipulated by reference, meaning that assigning a new value to the object will just update it and not all the other copies. We introduce a new assignement operator obj |= value that updates all the copies.

C++

var container = function (var data) { 
  var secret = data;
 
  return {
    _["set"] = function (var x) {
        secret |= x;
        return undefined;
    },
    _["get"] = function () { return secret; }
  };
};
 
var a = container("secret-a");
var b = container("secret-b");
 
a["set"]("override-a");
 
std::cout < < a["get"](); // override-a
std::cout << b["get"](); // secret-b
Javascript

var container = function (data) {
  var secret = data;
 
  return {
    set: function (x) {
        secret = x;
 
    },
    get: function () { return secret; }
  };
};
 
var a = container("secret-a");
var b = container("secret-b");
 
a.set("override-a");
 
console.log(a.get()); // override-a
console.log(b.get()); // secret-b

This

There are four ways to set the this value:

  • Function call: foo(). this is set to the global object. As this is not a proper way to do things, I set it to undefined.
  • Method call: object.foo(). this is set to object.
  • Constructor: new foo(). foo is called with a new instance of this.
  • Explicit: foo.call(this, arguments...). We explicitely set the this value.

All four ways are implemented in jspp but in a different way than Javascript. In Javascript, the language knows the construction and therefore can deduce what this is going to be. In C++, on the other hand, have a local view of what is going on. We have to develop another strategy for setting this that works for usual usage patterns.

We associate a this value for every object, by default being undefined. If we obtain the object through another object(test.foo), this is set to be the base object.

New creates a new function object with this set to itself. Therefore it can be called to initialize the object. Contrary to Javascript, the constructor function has to return this.

C++

var f = function (var x, var y) {
    std::cout < < "this: " << this;
    this["x"] = x;
    this["y"] = y;
    return this;
};
 
// New creates a new object this
var a = new (f)(1, 2); // this: [function 40d0]
var b = new (f)(3, 4); // this: [function 48e0]
 
// Unbound call, 
var c = f(5, 6); // this: undefined
 
// Bound call
var obj = {42};
obj["f"] = f;
 
var d = obj["f"](1, 2); // this: [42]
 
// Call
var e = f["call"](obj, 1, 2); // this: [42]
Javascript

var f = function (x, y) {
    console.log("this:", this);
    this["x"] = x;
    this["y"] = y;
 
};
 
// New creates a new object this
var a = new f(1, 2); // this: [object]
var b = new f(3, 4); // this: [object]
 
// Unbound call, 
var c = f(5, 6); // this: global object
 
// Bound call
var obj = [42];
obj["f"] = f;
 
var d = obj["f"](1, 2); // this: [42]
 
// Call
var e = f["call"](obj, 1, 2); // this: [42]

Prototypal Inheritance

In order to use prototypal inheritance, we can use Douglas Crockford Object.Create.

When reading a property, we try to read it on the current object, and if it does not exist we try again on the prototype. However, when writing a property we want to write it on the object itself. Therefore the returned object contains in fact two objects, one used for reading and one for writing.

C++

var createObject = function (var o) {
    var F = function () {return this;};
    F["prototype"] = o;
    return new (F)();
};
 
var Person = {
    _["name"] = "Default",
    _["greet"] = function () {
        return "My name is " + this["name"];
    }
};
 
var vjeux = createObject(Person);
vjeux["name"] = "Vjeux";
 
var blog = createObject(Person);
blog["name"] = "Blog";
 
var def = createObject(Person);
 
std::cout < < vjeux["greet"](); // Vjeux
std::cout << blog["greet"]();  // Blog
std::cout << def["greet"]();   // Default
Javascript

var createObject = function (o) {
    var F = function () {};
    F.prototype = o;
    return new F();
};
 
var Person = {
    name: "Default",
    greet: function () {
        return "My name is " + this.name;
    }
};
 
var vjeux = createObject(Person);
vjeux.name = "Vjeux";
 
var blog = createObject(Person);
blog.name = "Blog";
 
var def = createObject(Person);
 
console.log(vjeux.greet()); // Vjeux
console.log(blog.greet());  // Blog
console.log(def.greet());   // Default

Iteration

We use the new iteration facility of C++0x to deal with for(var in) Javascript syntax. We just define in to be :.

As this is a prototype, it currently loops over all the keys of the object. However, it is possible to implement the isEnumerable functionnality.

C++

var array = {10, 42, 30};
for (var i in array) {
    std::cout < < i << " - " << array[i];
}
// 0 - 10
// 1 - 42
// 2 - 30
// length - 3
// prototype - undefined
 
var object = {
    _["a"] = 1,
    _["b"] = 2,
    _["c"] = 3
};
for (var i in object) {
    std::cout << i << " - " << object[i];
}
// a - 1
// b - 2
// c - 3
// prototype - undefined
Javascript

var array = [10, 42, 30];
for (var i in array) {
    console.log(i, array[i]);
}
// 0 - 10
// 1 - 42
// 2 - 30
 
 
 
var object = {
    "a": 1,
    "b": 2,
    "c": 3
};
for (var i in object) {
    console.log(i, object[i]);
}
// a - 1
// b - 2
// c - 3
//

Dynamic Typing

There is only one class called var. All the operators +, +=, ++, < , * ... are overloaded in order to make the right behavior. Since this is only a prototype, all of them are not working properly nor following the ECMAScript standard.

C++

var repeat = function (var str, var times) {
    var ret = "";
    for (var i = 0; i < times; ++i) {
        ret += str + i;
    }
    return ret;
};
 
std::cout << repeat(" js++", 3);
// " js++0 js++1 js++2"
Javascript

var repeat = function (str, times) {
    var ret = "";
    for (var i = 0; i < times; ++i) {
        ret += str + i;
    }
    return ret;
};
 
console.log(repeat(" js++", 3));
// " js++0 js++1 js++2"

Scope

Scope management is done with lambdas. Since they are implemented in C++0x, it works without pain.

C++

var global = "global";
var $ = "prototype";
var jQuery = "jQuery";
 
_(function (var $) {
    var global = "local";
 
    std::cout < < "Inside:      $ = " << $;
    std::cout << "Inside: global = " << global;
 
    // Inside:      $ = jQuery
    // Inside: global = local
 
    return undefined;
})(jQuery);
 
std::cout << "Outside:      $ = " << $;
std::cout << "Outside: global = " << global;
 
// Outside:      $ = prototype
// Outside: global = global
Javascript

var global = "global";
var $ = "prototype";
var jQuery = "jQuery";
 
(function ($) {
    var global = "local";
 
    console.log("Inside:      $ = ", $);
    console.log("Inside: global = ", global);
 
    // Inside:      $ = jQuery
    // Inside: global = local
 
    return undefined;
})(jQuery);
 
console.log("Outside:      $ = ", $);
console.log("Outside: global = ", global);
 
// Outside:      $ = prototype
// Outside: global = global

Reference

As in Javascript, everything is passed by reference. The current implementation uses a simple reference count to handle garbage collection.

C++

var a = {};
a["key"] = "old";
 
var b = a;
b["key"] = "new";
 
std::cout < < a["key"] << " " << b["key"];
// new new
Javascript

var a = {};
a["key"] = "old";
 
var b = a;
b["key"] = "new";
 
console.log(a["key"], b["key"]);
// new new

Exception

Javascript exception mechanism is directly borrowed from C++, therefore we can use the native one.

We need to throw a Javascript object. We can either throw a new instance of a Javascript function or use _() to cast a string into an object.

C++

var go_die = function () {
    throw "Exception!";
};
 
try {
    go_die();
} catch (e) {
    std::cout < < "Error: " << e;
}
// Error: Exception!
Javascript

var go_die = function () {
    throw "Exception!";
};
 
try {
    go_die();
} catch (e) {
    console.log("Error:", e);
}
// Error: Exception!

How to use

Note: Only the strict minimum of code able to run the examples has been written. It is a prototype, do not try to use it for any serious development.

The library can be compiled under g++ 4.6, Visual Studio 2010 and the latest version of ICC. However Visual Studio and ICC do not support the initialization lists, so you cannot use the JSON syntax. But all the other examples will compile.

All the examples of this page are available in the example/ folder. The following execution will let you run the examples.

> make
g++ -o example/dynamic.jspp example/dynamic.cpp -Wall -std=gnu++0x
g++ -o example/exception.jspp example/exception.cpp -Wall -std=gnu++0x
...
> cd example
> ./json.jspp
{array: [1, 2, three], nested: {first: 1}, number: 42, string: vjeux}
> node json.js
{ number: 42,
  string: 'vjeux',
  array: [ 1, 2, 'three' ],
  nested: { first: 1 } }

Pro / Cons

The awesome part is the fact that it is possible to develop nearly all the concepts of Javascript in C++.

Pros

  • Write C++ in a dynamic fashion!
  • Extremely easy to integrate all the existing C++ code base.
  • Fun :)

Cons

  • Not possible to optimize as much as the latest Javascript engines.
  • Some features are impossible to write such as eval, with, named functions ...
  • No REPL.
  • A bit more verbose than Javascript.

How to Improve

  • Code the arguments management.
  • Develop the Javascript standard library (operators, Array, Regex ...).
  • Find ways to minimize the C++ overhead (remove the use of _()).
  • Find concepts that I did not introduce.

Stoyan Stefanov did a similar proof of concept but instead of targetting C++ he did it for PHP.

If you liked this article, you might be interested in my Twitter feed as well.
 
 

Related Posts

  • September 22, 2011 URLON: URL Object Notation (42)
    #json, #urlon, #rison { width: 100%; font-size: 12px; padding: 5px; height: 18px; color: #560061; } I am in the process of rewriting MMO-Champion Tables and I want a generic way to manage the hash part of the URL (#table__search_results_item=4%3A-slot). I no longer want to wr...
  • January 11, 2012 Javascript Ray Tracer (1)
    Here is a report of the Ray Tracer written by myself Christopher Chedeau. I've taken the file format and most of the examples from the Ray Tracer of our friends Maxime Mouial and Clément Bœsch. The source is available on Github. It is powered by Open Source technologies: glMatrix, CodeMirror, ...
  • November 5, 2011 Simulated Annealing Project (0)
    For a school project, I have to implement Simulated Annealing meta heuristic. Thanks to many open source web tools, I've been able to quickly do the project and have a pretty display. CoffeeScript, Raphael, Highcharts, Three.js, Twitter Bootstrap, jQuery and Web Workers. .hover-border img {...
  • September 17, 2011 WoW Interface Anchor Positioning (5)
    I've always found CSS positioning with both float and position: absolute/relative hard to work with. I want to introduce to you an alternative way borrowed from the World of Warcraft Interface: Anchors. Anchor The concept is extremely simple. You can tell where you want the element to be, rel...
  • August 13, 2012 Image Layout Algorithm – Facebook (1)
    Layout Algorithms: Facebook | Google Plus | Lightbox | Lightbox Android | 500px For the redesign of the Photo Section of Facebook we wanted to highlight some photos by making them bigger. It all started with the following mock by Andy Chung: Layout Alternated Blocks My first shot ...