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
Post a comment or leave a trackback: Trackback URL.

Comments

  • s3mm3l  On May 2, 2013 at 19:37

    My attempt uses the array-like bracket syntax to access the variables:
    function makePtr(parent, propertyName){
    return function(val){
    if (arguments.length > 0){parent[propertyName] = val;}
    return parent[propertyName];
    };}
    Test:
    var x = 1;
    var y = {value: 2};
    var xPtr = makePtr(window, ‘x’);
    var yPtr = makePtr(window, ‘y’);

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

    swap(xPtr, yPtr);

    // et voila!
    What do you think?

    • Amnon  On May 2, 2013 at 22:27

      It works only if you have a name for the parent scope. For example, I don’t think it would work with local variables.

      • s3mm3l  On May 3, 2013 at 15:47

        Yes you are right, there is now way to get to the function invocation “call object”.
        Therefore my solution with the bracket access works just for properties of the global or some user object.

        However since I’ve been warned about the security of the eval function, I’ll perhaps accept this limitation.
        For example:
        var yPtr = makePtr(‘(function(){console.log(“I could do anything right now”);})()’);

    • Amnon  On May 3, 2013 at 17:08

      eval is only insecure if you give it user-supplied data. There will be no problem if you always use a constant string as a parameter (makePtr(‘x’)). You could also add a check to the function to make it accept only identifiers.

  • Z. Khullah  On October 17, 2015 at 16:01

    First, the issue here is about passing references of variables to functions. If one try to swap outside a function, it would work shamelessly:

    var x = 1;
    var y = { value: ‘b’ }
    console.log(x, y);

    var z = {}
    z = x;
    x = y;
    y = z;
    console.log(x, y);

    About the “pointer” function, it doesn’t work because when you pass a variable (not an object) to a function, javascript will pass it by reference – so the console shows the right values, but is a copy of the original. Since variables are mostly inexpensive, this just isn’t relevant.

    If you pass an object, than IT WILL pass it by reference:

    var o = { x: 1}
    console.log(o);

    function ByRef(obj) {
    obj.x = 2;
    }
    ByRef(o);
    console.log(o);

    However, if you still want to pass a variable as reference, than the trick should be much similar than of pointers – don’t pass the variable, but something (some value) that allows you to access the same variable. In C, you also can’t pass by reference, and instead you can send the memory address (aka pointer) where the variable is located. In javascript, the idea of relating to the parent is the equivalent: send a varname that is bounded to an object reference, so we can access it through parent[varname].

    Now, calling a function(parent, variablename) is a good idea, but you don’t need a makePointer function. The parent will be passed on by reference and it will work directly in the swap function:

    var x = { value: ‘a’ }
    var y = { value: ‘b’ }
    console.log(x, y);

    function swap(parent1, parent2, p) {
    var z;
    z = parent1[p];
    parent1[p] = parent2[p];
    parent2[p] = z;
    }

    swap(x, y, ‘value’);
    console.log(x, y);

    Aditionally, its possible to define a ‘parent’ to a function so you can just call it by function(variablename). Then the parent/context is the ‘this’ keyword. There’s 2 ways of doing that:

    1) specifying the parent/context when calling the function, via ‘funcname’.call(parent, …). The first argument will become the ‘this’ inside the function, and the rest of the arguments should be passed normally starting at the second one

    2) fixing the parent to the function via ‘funcname’.bind(parent), so whenever you call it normally (without the call method), the ‘this’ is always the parent.

    Conclusion: you dont need pointers. javascript passes variables as values, and objects as references. Also the context inside the function can be defined a priori or a posteriori.

    Any thoughts appreciated.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: