3

I'm using dynamic scoping to simulate pointers in JavaScript as follows:

var ptr = (function () {
    var ptr = "(" + String(function (value) {
    if (value === void 0) return upvalue;
    else upvalue = value;
}) + ")";

    return function (upvalue) {
        return ptr.replace(/upvalue/g, upvalue);
    };
}());

function swap(xptr, yptr) {
    var t = xptr();
    xptr(yptr());
    yptr(t);
}

var x = 2;
var y = 3;

alert([x, y]);
swap(eval(ptr("x")), eval(ptr("y")));
alert([x, y]);

Is there any other way to achieve the same results (i.e. without resorting to eval)? It just seems like too much boilerplate.

17
  • 4
    Why do you want to do this? Generally speaking, if you try to write JavaScript like it's a different language you're going to end up with some really ugly code. Commented Apr 23, 2012 at 13:06
  • 4
    Ugh, that's wrong on so many levels... Is there any particular problem you want to solve or is this an academic question? Commented Apr 23, 2012 at 13:07
  • 1
    If you need pointers without eval use arrays. Commented Apr 23, 2012 at 13:08
  • @JamesMcLaughlin - It doesn't matter if the code is ugly. It's just boilerplate for a language that I'm building on top of JavaScript (like CoffeeScript). The end user doesn't need to interact with the JavaScript boilerplate at all. Hence it's alright if it's not pretty. =) Commented Apr 23, 2012 at 15:19
  • 1
    Maybe I just don't understand what problem you are trying to solve. I don't see any benefit in pointers within the context of JavaScript. But I do see you using eval and mutating stringified function bodies with regular expressions and that can't be right. For one: There are no "memory locations" in a memory-managed language. Further: Big and complex JS libraries have been written without the need to "simulate" pointers. It just does not make sense to me, and it probably won't until you can point out a reasonable use case. Commented Apr 24, 2012 at 7:29

5 Answers 5

5

Since the only thing you're using the pointer for is to dereference it to access another variable, you can just encapsulate it in a property.

function createPointer(read, write) {
  return { get value() { return read(); }, set value(v) { return write(v); } };
}

To create a pointer, pass the accessor methods which read and write the variable being pointed to.

var i;
var p = createPointer(function() { return i; }, function(v) { i = v; });
// p is now a "pointer" to i

To dereference a pointer, access its value. In other words, where in C you would write *p here you write p.value.

i = "initial";
alert(p.value); // alerts "initial"
p.value = "update";
alert(i); // alerts "update"
p.value += "2";
alert(i); // alerts "update2"

You can create multiple pointers to the same variable.

var q = createPointer(function() { return i; }, function(v) { i = v; });
// q is also a "pointer" to i
alert(q.value); // alerts "update2"
q.value = "written from q";
alert(p.value); // alerts "written from q"

You can change what a pointer points to by simply overwriting the pointer variable with another pointer.

var j = "other";
q = createPointer(function() { return j; }, function(v) { j = v; });
// q is now a "pointer" to j

You can swap two variables through pointers.

function swap(x, y) {
    var t = x.value;
    x.value = y.value;
    y.value = t;
}

Let's swap the values of i and j by using their pointers.

swap(p, q);
alert(i); // alerts "other"
alert(j); // alerts "written from q"

You can create pointers to local variables.

function example() {
    var myVar = "myVar as local variable from example";
    var r = createPointer(function() { return myVar; }, function(v) { myVar = v; });
    swap(p,r);
    alert(i); // alerts "myVar as local variable from example"
    alert(myVar); // alerts "other"
}
example();

Through the magic of closures, this gives you a way to simulate malloc.

function malloc() {
    var i;
    return createPointer(function() { return i; }, function(v) { i = v; });
}
var p = malloc(); // p points to a variable we just allocated from the heap
p.value = 2; // write a 2 into it

Your magic trick works too:

var flowers = new Misdirection(
       createPointer(function() { return flowers; }, function(v) { flowers = v; }));
flowers.abracadabra();
alert(flowers);

function Misdirection(flowers) {
    this.abracadabra = function() {
        flowers.value = new Rabbit;
    };
}

function Rabbit() {
    this.toString = function() { return "Eh... what's up doc?" };
}
Sign up to request clarification or add additional context in comments.

3 Comments

This is exactly what I was looking for. Thank you. I guess I stand corrected about using properties to simulate pointers. However as exciting as this is I'm afraid it may not work in older browsers (getters and setters aren't supported in older browsers), so we'll still have to use my method as a fallback. Nevertheless, greatly appreciated. =)
You can simulate properties with explicit get and put methods.
Maybe shorter: function createPointer(r, w) { return Object.defineProperty({}, "value", {get: r, set: w}); }
2

Unfortunately, the only ways to reference a variable in Javascript are accessing it directly (something we don't want, since it does static binding) or passing its name in string form to eval.

If you really want to avoid eval, what you can do is try to have your variables inside objects that act as scopes, since this would let you use [] subscript notation to access a variable given its name. Note that if all pointers you create are to global variables then this is already the case, since global variables are also made to be properties of the global window object.


function pointer(scope, varname){
    return function(x){
        if(arguments.length <= 0){ //The explicit arguments.length lets us set the pointed variable to undefined too.
            return scope[varname];
        }else{
            return (scope[varname] = x);
        }
    }
};

var vars = {
    x: 1
};

var y = 2; // "normal" variables will only work if they are global.

swap( pointer(vars, 'x'), pointer(window, 'y') );

1 Comment

+1 for allowing the pointer to point to undefined (although I think that null would be a better placeholder for nothing since undefined is meant specifically for variables and properties which haven't been defined as yet). Nevertheless, like I commented on other answers I need the pointers to point to global or local variables and not properties of an object. So I guess closures are the only way of implementing that. :|
0

something like that?

function swap(a,b,scope) {
    var t = scope[a];
    scope[a] = scope[b];
    scope[b] = t; 
}

x = 2;
y = 3;
alert([x,y]);
swap('x', 'y',this);
alert([x,y]);

1 Comment

No. In this case we either have to use global variables or properties of an object. All variables are properties of an activation object but we don't have access to the activation object so this method won't work.
0

Here is one way of doing it with an object:

var obj = {
    x:2,
    y:3
},
swap = function(p1, p2){
    var t = obj[p1];
    obj[p1] = obj[p2];
    obj[p2] = t;
};

console.log( obj.x, obj.y );
swap('x', 'y');
console.log( obj.x, obj.y );

4 Comments

This answer is similar to that posted by @chumkiu below. However like I said, I need to use variables and not properties of an object; and since we can't access the activation object of functions it'll only work for global variables (which is exactly what we don't want).
A variable is a property of the window object. And you can use a global object window.yourObject like all the JS lib out there.
That's not true for local variables. Plus it's better if we don't populate the global scope with lots of variables.
if you wrap my code in a (function(){...})() the variable are not global anymore, and you can use them as closures inside. Many JS libs add a single global variable: $, dojo, jQuery,... with their own methods.
0

Edit:

@Tomalak - Consider the following JavaScript program:

var flowers = new Misdirection;
flowers.abracadabra();
alert(flowers);

function Misdirection() {
    this.abracadabra = function () {
        this = new Rabbit;
    };
}

function Rabbit() {
    this.toString = function () {
        return "Eh... What's up, doc?";
    };
}

The above program throws ReferenceError: Cannot assign to 'this'. Pointers can be used to solve this problem; and although it won't update the this pointer, it will do the next best thing - update the only reference to the this pointer.

We could make the above program work without using pointers by replacing this with flowers. However by doing so the misdirection magic trick will only work for one instance of the constructor. Pointers allow us to make it work for any number of instances.

It's not possible to achieve the same results by using Function.call, Function.apply, or Array.map. In addition if the constructor returns an explicit value then it's useless to override the this pointer anyway. The program I wrote below (using pointers) will work even if I returned the abracadabra function from Misdirection and called flowers() instead of flowers.abracadabra().

Original:

Simulating pointers in JavaScript is a really powerful hack. For example it can be used to perform a magic trick as follows:

var flowers = new Misdirection(&flowers);
flowers.abracadabra();
alert(flowers);

function Misdirection(flowers) {
    this.abracadabra = function () {
        *flowers = new Rabbit;
    };
}

function Rabbit() {
    this.toString = function () {
        return "Eh... What's up, doc?";
    };
}

That's all nice and dandy, but the real power of simulating pointers in JavaScript shines through when we push the envelope:

var Square = new Class(function (ctor, uber) {
    *ctor = constructor;

    var side;

    function constructor(length) {
        side = length;
    }

    this.area = function () {
        return side * side;
    };

    return &uber;
});

var Cube = new Class(function (ctor, uber) {
    *ctor = constructor;

    function constructor(side) {
        uber(side);
    }

    this.area = function () {
        return 6 * uber.area();
    };

    return &uber;
}, Square);

var cube = new Cube(5);
alert(cube.area());

function Class(claus, Uber) {
    Claus.__proto__ = Uber === void 0 ? Class.prototype : Uber;

    return Claus;

    function Claus() {
        var self = this;
        var called;

        var uber = Uber === void 0 ? function () {
            throw new Error("No uber class specified.");
        } : function () {
            if (!called) {
                called = "Cannot call uber class constructor more than once.";

                var args = Array.prototype.slice.call(arguments);
                args = Array.prototype.concat.call([null], args);
                var base = new (Function.prototype.bind.apply(Uber, args));

                self.__proto__.__proto__ = base;
                self.__proto__.__proto__.constructor = Claus;

                *uber = base;
            } else throw new Error(called);
        };

        var constructor = new Function;
        uber = claus.call(this, &constructor, uber);
        constructor.apply(this, arguments);
    };
}

Obviously this is too much boilerplate, but it does demonstrate just how powerful closures are. What's truly amazing is that we can use this boilerplate to simulate classical object oriented programming in JavaScript. For example the following code can be transcompiled to the above program (although we'll need to write a full fledged parser to do so):

class Square {
    var side;

    function constructor(length) {
        side = length;
    }

    this.area = function () {
        return side * side;
    };
}

class Cube extends Square {
    function constructor(side) {
        uber(side);
    }

    this.area = function () {
        return 6 * uber.area();
    };
}

var cube = new Cube(5);
alert(cube.area());

Notice that the lines *ctor = constructor; and return &uber; have been removed. This is just redundant code necessary to make the constructor and inheritance work. Also the Class function is not written in the source as it's automatically added by the transcompiler.

The beauty of simulating pointers in JavaScript is demonstrated in the above program where the variable uber in the class Cube is initially the base class constructor function. However when it's called it's replaced by that instance of the base class which becomes the prototype of this.

It also means that an instance of Cube will not be an instance of Square unless and until the uber class constructor is called from Cube.

3 Comments

It seems that what you are simulating is not pointers but variable references. These can easily be simulated via properties.
No. What I'm simulating is in fact a pointer. Reference variables once initialised do not need to be dereferenced. They are simply an alias for another variable. In addition they are constant variables. They cannot be modified. You are confused between a reference and a reference variable. References are aliases for values. Reference variables are aliases for variables. What I'm simulating is a pointer to a variable. It's not the same as a property and the same use cases can't be implemented using properties.
You are not performing any pointer operations beyond dereferencing. (No pointer arithmetic for example.) You can therefore just use a Javascript property to perform the dereferencing.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.