Simulating pointers in JavaScript, part 2

In the previous post we saw how we can simulate pointers in JavaScript using closures. When we want to create a pointer to a variable, we actually create a function that references that variable:

    var x;
    // ...
    var xptr = function(val) {
        if (arguments.length > 0) x = val;
        return x;
    }

This scheme works, but it means duplicating the function code every time a pointer is created.

Usually you can prevent code duplication by factoring out the common code. When I considered it, my first thought was to write a function (a pointer constructor) that accepts a variable and returns a pointer to that variable. But this brings us back to the original problem of creating a pointer, since in JavaScript you don’t pass a variable to a function; you only pass its value.

What we need is actually a kind of macro — a function that more or less rewrites part of the source code. The macro would ideally inject the pointer definition shown above, with the correct variable name, whenever we need it. The closest thing to macros in JavaScript is eval(), which accepts a string and executes it as part of the current environment. We’ll just use a function that accepts a variable name and returns a script excerpt that does what we want:

function makePtr(varName) {
    return "(function(_val) {\n" + 
        "    if (arguments.length > 0) " + varName + " = _val;\n" + 
        "    return " + varName + ";\n" +
        "})";
}

function swap(ptr1, ptr2) {
    var t = ptr1();
    ptr1(ptr2());
    ptr2(t);
}

function testit() {
    var x = 1, y = 2;
    print(x,y);
    swap(eval(makePtr("x")), eval(makePtr("y")));
    print(x,y);
}

testit();

The script is identical to the original one, except that function makePtr() writes the code for us — we just need to execute the code with eval(). (Again, if you don’t have a print() function you’ll have to make one yourself).

So now we can create pointers easily. The syntax for using the pointers is still not good enough: for example, assignment doesn’t look like assignment at all. Later I’ll show a possible solution for this.

Advertisements

Simulating pointers in JavaScript

(If you already know about pointers and want to see them in JavaScript, feel free to skip the first few paragraphs).

A basic notion in the C and C++ programming languages is that of pointers. A pointer is basically a variable through which you can access (read or modify) another variable. For example, a function A can call function B and pass it a pointer to one of A’s local variables. Function B can then modify that variable through the pointer, even though it can’t access A’s local variable directly.

Pointers are commonly used to implement “call-by-reference”. An example that we’ll be using here is that of a swap function, that accepts two variables and exchanges their values. After calling swap(x, y) we’ll want to find that x now contains the former value of y, and vice versa. In fact, this isn’t possible in C, nor in JavaScript, since these languages always pass arguments by value. Whatever swap() does, it can’t change the values of x and y, since it only receives a copy of their values. We can, however, give it pointers to x and y, through which it will be able to change their values.

This works great in C/C++, but what can we do in JavaScript, where we don’t have pointers?

One possible way to deal with this is to note that when we call a JavaScript function with an argument x, the function can’t assign a new value to x, but it can modify x’s current value. To make a concrete example:

function f(arg) {
   arg.value = "Hi";
}

var x = {};
f(x);
alert(x.value); // says hi

After calling f(x), x still refers to the same object, but one of the properties on the object has changed. This is a possible way to implement “out parameters”, but it’s not what we want. What if x is an immutable data type (that can’t be modified) such as a Number? Or what if we want to point to an arbitrary property of x?

The solution is using closures. When you define a function inside of another function, the inner function can reference that outer function’s variables. An important fact in JavaScript is that you can pass functions around like normal objects. Closures mean that when you pass the inner function around, the outer function’s variables it references go along with the inner function. Here is a first draft of how closures can be used to simulate pointers:

function swap(ptr1, ptr2) {
    var t = ptr1();
    ptr1(ptr2());
    ptr2(t);
}

function testit() {
    var x = 1, y = 2;

    var xptr = function(val) {
        if (arguments.length > 0) x = val;
        return x;
    }

    var yptr = function(val) {
        if (arguments.length > 0) y = val;
        return y;
    }

    print(x,y); // prints 1 2
    swap(xptr, yptr);
    print(x,y); // prints 2 1
}

testit();

(I’m using the print() function from V8 shell, which isn’t available in web browsers. I’m sure you can find another way to print the results if necessary).

As you can see, the pointer to a variable is actually a function. When you call the function with no arguments, it returns the variable’s current value. When you call the function with an argument, it performs an assignment to the variable.

This is very nice, but writing a 4 line function every time you want to create a pointer can be pretty tedious and error prone. How can you make pointer definitions easier? All this and more in a future post.