Contact GeekHive

Cleaner Code, One Proxy at a Time

September 26, 2014

Blog | Uncategorized | Cleaner Code, One Proxy at a Time
Cleaner Code, One Proxy at a Time

Metaprogramming is the means by which a programmer changes how a program or language works, usually dynamically. In many languages, this surfaces as public APIs that override standard behaviors.
Different languages offer differing metaprogramming interfaces. C and C++ have the macro preprocessor. C++ also has templates. C# offers operator overloading and the Reflection library which are forms of metaprogramming.

In Ruby, metaprogramming surfaces as the methods which allow people to monkeypatch their classes with new methods at runtime, and dynamically respond to method invocations with handlers like method_missing. Through metaprogramming, developers typically seek to improve the clarity and succinctness of their code. This can be seen through small improvements, like overloading obja + objb with obja.add(objb), or much grander shortenings like those performed by cspec‘s macros.

JavaScript doesn’t have any of these traditional metaprogramming interfaces. Given how dynamic it is (you can monkeypatch prototypes freely), this may come as a surprise to some. For example, in Ruby I could write a Tuple-like class like so:

require 'numerizer'

class Tuple < Array
    def method_missing(method, *args, &block)
        invocation = if method.to_s.end_with? "=" then :[]= else :[] end

        if method == :second || method == :second=
            #Numerizer doesn't parse 'second' correctly
            return self.send invocation, 1, *args

        slot = Numerizer.numerize(method.to_s).to_i

        if slot>0 && slot<=self.length
            return self.send invocation, slot-1, *args
        super #let ruby handle the invocation

    def respond_to?(method, include_private=false)
        if method == :second || method == :second=
            return self.length>=2
        slot = Numerizer.numerize(method.to_s).to_i
        puts self.length.to_s
        (slot>0 && slot<=self.length) || super

    def +(other)

#So we can use it like so
tuple =
tuple.first = 1
tuple.second = 2
tuple.third = 3
tuple.fourth = 4

tuple.first == 1 or puts "First was not set"
tuple.second == 2 or puts "Second was not set"
tuple.third == 3 or puts "Third was not set"
tuple.fourth == 4 or puts "Fourth was not set"

tuple += [ :five! ]
tuple.fifth == :five! or puts "Fifth was not set"

Whereas in JavaScript that kind of dynamic method checking/forwarding is actually just impossible, since there's no (standard) way to intercept the method calls.

In, the next JavaScript language specification, all that changes with the introduction of the Proxy object. The above Tuple class, in JavaScript (without using any new ES6 goodies other than Proxy):


    var overrides = {
        get: function(target, key) {
            var num = parseInt(numerizer(key));
            if (num && num>0 && num<=target.length) {
                return target[num-1];
            return target[key]; //Optionally, throw if undefined to emulate ruby behavior
        set: function(target, key, value) {
            var num = parseInt(numerizer(key));
            if (num && num>0 && num<=target.length) {
                return target[num-1] = value;
            return target[key] = value;

    var Tuple = function(size) {
        var data = new Array(size);
        return new Proxy(data, overrides);

    window.Tuple = Tuple;

Fancy. Unfortunately, this also showcases some of the limitations that still exist. Whereas in Ruby, we could overload the + operator to return our new Tuple object, in JavaScript we have no mechanism to overload operators. All +/-/etc operators do coercive calls under the hood to make them into either a string or integer (via toString or valueOf, respectively) and use a predefined internal method on them. For the same reason, the key argument to a proxy will always either be a string or a number - the key is coerced under the hood by the internal [[Get]] or [[Set]] slot.

This is still super useful, since you could create a proxy over, say, a REST service so that you can use it like so:

var server = REST('');
var routes = server(); //Return a Promise to the response
var emojis = server.emojis();
var gists = server.gists.public();


Which language feature are you most excited for in the upcoming language release? Tweet to us @GeekHive.

Wesley Wigham

  • JavaScript

Recent Work

Check out what else we've been working on