From: nick on
Well, it's the weekend again, time for more experimental fun with
js :)

Last week I was trying to pass primitives by reference (or, more
precisely, passing mutable object wrappers representing
primitives) ... anyway the point was to be able to do stuff like this
(pseudocode):

func ModifyValue(a,b) { increase a by b; }
let x = 4;
ModifyValue(x, 3);
print(x); // x is now 7

Now, last time I tried to accomplish this by adding function
properties to Object's prototype, which as I learned is a Bad Thing
(it breaks iterating over object properties using 'for ... in'). This
time I'm trying another approach; again I'd love to hear feedback from
you guys...

This time, instead of modifying Object's prototype, I'm modifying
prototypes only for constructors of primitive types. Before I go on
with the implementation, this brings up my first worry... a String, in
some browsers, acts as a collection of characters-as-strings with
'for ... in.' Does anyone actually use that functionality, or is it ok
to add stuff to String's constructor?

More generally, will it be a huge performance hit if I modify
constructors for Boolean, Integer, and String with one small function
property?

Alright, here we go:
....

(function(){
var p = [Boolean,Number,String];
for(var t in p) p[t].prototype.set =
function(v) { return wrap(Object(this), v) }
function wrap(o, v)
{
var c = o.constructor;
o.value = v===undefined ? c(o) : v ? c(v) : c();
o.valueOf = function() { return o.value.valueOf() }
o.toString = function() { return o.value.toString() }
o.set = function(v) { o.value = v ? c(v) : c(); return o }
return o;
}
})();

....
This extends [Boolean,Number,String].prototype with a method 'set'
that changes the current object by adding a property 'value' and
overriding valueOf and toString to return 'value'.

On the fourth line, 'Object(this)' is needed instead of just 'this'
for Chrome to act as expected when using the "// this works too"
notation below. The rest should be pretty straightforward. Here's a
quick test:
....

// some test functions
function square(n) { n.set(n*n) }
function bold(n) { n.set('<b>'+n+'</b>') }

// let's do some tests...

var foo = new Number(5);
// var foo = (5).set(); // this works too
var bar = foo;
alert(bar);

square(bar);
alert(foo);

bar.set(3);
square(foo);
alert(bar);

var baz = new String("asfaf");
// var baz = "asfaf".set(); // this works too
bold(baz);
alert(baz);

....

Thoughts? Criticisms? Cries of outrage from PE? Can't wait to hear
'em :)

-- Nick
From: Asen Bozhilov on
nick wrote:

> (function(){
>   var p = [Boolean,Number,String];
>   for(var t in p) p[t].prototype.set =

For-in lookup in prototype chain, and enumerate properties which
doesn't have {DontEnum} attribute. You should filter properties, which
inherited from objects in prototype chain.

>     function(v) { return wrap(Object(this), v) }

Object(this)? Why do you call `Object' constructor? The `this' value
always refer `object' in ECMA 262-3
implementations.

>   function wrap(o, v)
>   {
>     var c = o.constructor;
>     o.value = v===undefined ? c(o) : v ? c(v) : c();
>     o.valueOf = function() { return o.value.valueOf() }
>     o.toString = function() { return o.value.toString() }
>     o.set = function(v) { o.value = v ? c(v) : c(); return o }
>     return o;
>   }
>
> })();

And every time when i call `set' method, you create two new functions.

var x = new Number(10);
x.set(50);

| 1. assign to `valueOf' reference to `object' which internal
[[Prototype]] refer Function.prototype
| 2. assign to `toString' reference to `object' which internal
[[Prototype]] refer Function.prototype

x.set(10);

| 3. same as a step 1.
| 4. mark `object' from step 1 for garbage collection
| 5. same as a step 2
| 6. mark `object' from step 2 for garbage collection


From: nick on
On Jan 23, 1:29 pm, Asen Bozhilov <asen.bozhi...(a)gmail.com> wrote:
> nick wrote:
> > (function(){
> >   var p = [Boolean,Number,String];
> >   for(var t in p) p[t].prototype.set =
>
> For-in lookup in prototype chain, and enumerate properties which
> doesn't have {DontEnum} attribute. You should filter properties, which
> inherited from objects in prototype chain.
>

Thanks for your response. Not sure I understand what you mean here,
I'll think on it more.

> >     function(v) { return wrap(Object(this), v) }
>
> Object(this)? Why do you call `Object' constructor? The `this' value
> always refer `object' in ECMA 262-3
> implementations.
>

Already noted... On the fourth line, 'Object(this)' is needed instead
of just 'this' for Chrome to act as expected...

> >   function wrap(o, v)
> >   {
> >     var c = o.constructor;
> >     o.value = v===undefined ? c(o) : v ? c(v) : c();
> >     o.valueOf = function() { return o.value.valueOf() }
> >     o.toString = function() { return o.value.toString() }
> >     o.set = function(v) { o.value = v ? c(v) : c(); return o }
> >     return o;
> >   }
>
> > })();
>
> And every time when i call `set' method, you create two new functions.
>
> var x = new Number(10);
> x.set(50);
>
> | 1. assign to `valueOf' reference to `object' which internal
> [[Prototype]] refer Function.prototype
> | 2. assign to `toString' reference to `object' which internal
> [[Prototype]] refer Function.prototype
>

Is this coming from some debugging code you have or did you write it?

Anyway, missed |3., which (re)assigns to set an anonymous function (v)
which basically does 4. and 6. below

> x.set(10);
>
> | 3. same as a step 1.
> | 4. mark `object' from step 1 for garbage collection
> | 5. same as a step 2
> | 6. mark `object' from step 2 for garbage collection

....but set has changed, and no longer calls wrap() ... it sets the
internal object you are referring to directly. So valueOf and toString
should only be set once. I think 3. and 5. should not happen.

-- Nick
From: nick on
On Jan 23, 1:49 pm, nick <nick...(a)fastmail.fm> wrote:

> which basically does 4. and 6. below
>
> > x.set(10);
>
> > | 3. same as a step 1.
> > | 4. mark `object' from step 1 for garbage collection
> > | 5. same as a step 2
> > | 6. mark `object' from step 2 for garbage collection
>

wait, no it doesn't. I read your post too quickly. What it does is set
the object's 'value' property to something else (which I assume will
casue the GC to clean up the old value). So none of this should be
happening.
From: Asen Bozhilov on
nick wrote:

> Thanks for your response. Not sure I understand what you mean here,
> I'll think on it more.

See above:

Array.prototype.o = Object;
var p = [Boolean,Number,String];
for(var t in p)
{
p[t].prototype.set = function(v) {
return wrap(Object(this), v);
};
}

You can filter with `hasOwnProperty' or with normal `for` loop:

for (var i = p.length; p--;)
{
p[i].prototype.set = function(){};
}

window.alert(typeof Object.prototype.set); //function

> ...but set has changed, and no longer calls wrap() ... it sets the
> internal object you are referring to directly. So valueOf and toString
> should only be set once. I think 3. and 5. should not happen.

Yes, my mistake. I did see overriding `set'. However, i still miss
general idea. Why do you want this? If you want explicit pointers you
can write in some low level language like `C`.

Regards.
 |  Next  |  Last
Pages: 1 2
Prev: jQuery vs. My Library
Next: try catch catches when