From: nick on
On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de>
wrote:
....
> - $-prefixed property names are a problem for many reasons; avoid them
>   as recommended by Edition 3 Final of the (ECMAScript) Specification.

Ok, I just had a look through a pdf document I found on mozzila's
(sorry, web) site titled Edition 3 Final ECMAScript Language
Specification:

http://www.mozilla.org/js/language/E262-3.pdf

Did a ctrl-f for "$" and "dollar," the only thing I see about it
(besides some stuff about string matching and regular expressions) is:

##

This standard specifies one departure from the grammar given in the
Unicode standard: The dollar sign ($) and the underscore (_) are
permitted anywhere in an identifier. The dollar sign is intended for
use only in mechanically generated code.

##

.... I didn't see where it recommended avoiding them, am I looking at
the wrong document?

-- Nick
From: Garrett Smith on
nick wrote:
> On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de>
> wrote:
>> nick wrote:

[...]
> Object.prototype.$ = function(memberName)
[...]
> ...does that look any better?
>
No. Identifier `$` has no meaningful value.

Modifying object.prototype breaks for-in loops.
--
Garrett
comp.lang.javascript FAQ: http://jibbering.com/faq/
From: Thomas 'PointedEars' Lahn on
nick wrote:

> Thomas 'PointedEars' Lahn wrote:
> [...]
> // Get mutable object from primitive value, or a reference
> // to an object member if memberName is provided.
> Object.prototype.$ = function(memberName)
> {
> if (!memberName)
> return Object(this);
> v = function() { return this.$_object[this.$_member] };
> return {$_object:this, $_member:memberName, valueOf:v, toString:v};
> };
>
> // Set the value of current object.
> Object.prototype.$_ = function(value)
> {
> if (this.$_object)
> this.$_object[this.$_member] = value;
> else
> this.valueOf = this.toString = function() { return value };
> return this;
> };
>
> ##
>
> Alright, let me try to address some of your points.
>
> [...]
>> - You want to avoid augmenting Object.prototype.
>
> I'm not sure I do. How else will I be able to do things like this:
>
> var foo = document.body.style.$('backgroundcolor');

Bad inference. The `style' property of those objects does _not_ refer to a
native object (but to a host object), so you cannot expect it to inherit
from Object.prototype or be extensible.

> foo.$_('red'); // background of page turns red

No, it will not. Not least because the correct property name is
`backgroundColor'.

> document.body.style.backgroundcolor = 'black';
> // value of foo is now 'black'

Nobody wants to do that. Think of the performance penalty when calling a
prototype method -- and for what?

>> - Objects have identity, not name.
>
> Where did I say objects had names? Are you referring to this:
>
> "The '$' method will accept a single string parameter. If present, the
> returned value will be a special reference to the named object member.
> The result will appear to be a simple value, but it is linked with the
> object member."
>
> I meant here that the member of the object is named, not that the
> object is named. The reference is to the member, not the object.

Do not let yourself be confused by the term `MemberExpression' in the
Specification: those are _not_ members, they are _properties_ (the term
"member" is only use for members of built-in *data types* in the
Specification). Properties can hold values. If they hold references to
objects (which are values), then that referred object has identity, not
name: it can be referred to by properties of different name of different
objects. However, you are false assuming that an object can only ever be
referred to by the same property, as your wrapper object has a property to
store only that one property's name.

>> - You can only ever consider global variables or other properties
>> of the Global Object with this, as the Activation Object of
>> local execution contexts cannot be referred to.
>
> Can you clarify? I don't understand this.

I think I was mistaken; `this' does not refer to an Activation Object here.

However, the `$_object' property (regardless of its name) does not make
sense except as a marker because its value is a reference to the calling
object (`this'): this.$_object[this.$_member] === this[this.$_member].
BTW, there's another potential problem: You try to the augment the instance
with a property `$_member', a property that becomes enumerable when set,
and error-prone to rely on when not set.

The supposed-to-be type-cast `Object(this)' is also pointless because in
the context in which it is used, `this' is already a reference to an
object; or, IOW, `this' *always* refers to an object (for primitive values:
due to the built-in wrapping object) and does not need to be type-casted
(provided that was possible so easily). Incidentally, when the Object()
function is called as a function or a constructor with an object reference
as argument, it simply returns that reference without creating a new object
(ES3/5, 15.2.1.1 and 15.2.2.1).

>> - toString() should return a primitive string value.
>
> I'd expect it to with this code. Are you suggesting I force the result
> to a primitive?

You better do, for which you would need to backup the original toString()
method.

>> - The modification does not work transparently; all code would
>> need to be rewritten -- to be considerably less efficient afterwards.
>
> How could it possible work transparently,

See my example. All that is additionally required then is defining a
setter (with Object.protoype.__defineSetter__ and the like; not fully
compatible, though); but then one could have used native setters and
getters to begin with.

> as the language doesn't support any concept of pointers?

Non sequitur.

> Using this would require rewriting all code, it just requires: (1) wrap
> primitive in an object so you can use the $_() setter, and (2) use the
> $_() setter to set a value when you want to modify the value "by
> reference."

And it would require rewriting of all functions and methods that used the
wrapper object instead of the primitive value. Even though they only
required read access.

>> - Concept error: Nobody sane would not want to *modify* *constants*.
>
> Where did I modify constants? Not sure what you mean here either.

`5' is a constant as is `"foo"'. Constant as in immutable. One would not
attempt to modify immutable values, or emulate that by keeping a wrapper
object to store another value. There is no advantage in doing that over
working with the primitive value, and there are several possible
disadvantages, some of which I have mentioned. So it remains a nice idea,
good for theoretical discussion what is possible, but not a practical one.

> Here's a modified snippet....
> [...]
> ...does that look any better?

Hardly.

Please learn to quote; trim your quotes to the relevant parts.

<http://jibbering.com/faq/#posting> pp.


PointedEars
--
Use any version of Microsoft Frontpage to create your site.
(This won't prevent people from viewing your source, but no one
will want to steal it.)
-- from <http://www.vortex-webdesign.com/help/hidesource.htm> (404-comp.)
From: nick on
On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <PointedE...(a)web.de>
wrote:
....
> ECMAScript has built-in objects for most primitive types already that are
> automatically used as wrapper objects and can do what you want.  You could
> augment *their* prototypes instead:
>
>   Number.prototype._setValueOf = function() {
>     var v = this.valueOf();
>     Number.prototype.valueOf = function() {
>       return (typeof this.value != "undefined") ? this.value : v;
>     };
>   };
>
>   Number.prototype.plus = function(operand) {
>     this._setValueOf();
>     this.value = this + operand;
>     return this;
>   };
>
>   var x = (2).plus(3);
>   x.plus(1);
>
> But probably this is not a particularly good idea either.


Overriding Number instead of Object seems like a worse solution to me.
It doesn't work as you might expect:

##

Number.prototype._set = function(value)
{
var v = value.valueOf();
this.valueOf = this.toString = function() { return v; };
return this;
};

function square(num)
{
num._set( num * num );
}


var a = 5;
square(a);
alert(a); // shows 5 -- as expected

var b = new Number(5);
square(b);
alert(b); // shows 25 -- this works

var c = Object(5);
square(c);
alert(c); // shows 25 -- this works

var d = [5];
square(d); // error: num._set is not a function
alert(d);

##

So, it looks like c was automatically converted to a Number, but d was
not... not what I expected! Compare to this:

##

// Set the value of current object.
Object.prototype._set = function(value)
{
var v = value.valueOf();
this.valueOf = this.toString = function() { return v; };
return this;
};

function square(num)
{
num._set( num * num );
}

var a = 5;
square(a);
alert(a); // shows 5 -- as expected

var b = new Number(5);
square(b);
alert(b); // shows 25 -- this still works

var c = Object(5);
square(c);
alert(c); // shows 25 -- this still works

var d = [5];
square(d);
alert(d); // shows 25 -- this *works*

##

Now we can use nice short object wrappers like [5] or ["blue"] and
this will work ... not to mention I don't have to mess with String
now, and any other primitive types I forgot about.

-- Nick

PS: sorry for atrocious spelling of Mozilla in previous post.
PPS: sorry for triple post ;)
From: nick on
On Jan 17, 2:18 pm, Thomas 'PointedEars' Lahn <PointedE...(a)web.de>
wrote:
> >> - You want to avoid augmenting Object.prototype.
>
> > I'm not sure I do. How else will I be able to do things like this:
>
> > var foo = document.body.style.$('backgroundcolor');
>
> Bad inference.  The `style' property of those objects does _not_ refer to a
> native object (but to a host object), so you cannot expect it to inherit
> from Object.prototype or be extensible.

Sure, but it works in every browser I've tested it in, and not just
for 'style,' so it seems consistent and useful...

>
> > foo.$_('red'); // background of page turns red
>
> No, it will not.  Not least because the correct property name is
> `backgroundColor'.
>

Touche ;)

> ... you are false assuming that an object can only ever be
> referred to by the same property, as your wrapper object has a property to
> store only that one property's name.

I don't really see the problem here... even if the object is referred
to by other properties, my wrapper object only needs to know one way
to find it in order to modify and read its value. In other words,

var bob = {name:'bob', age:33};
var bobsDad = {son:bob, rel:'dad'};
var bobsKid = {dad:bob, rel:'son'};

var p = bobsDad.son.$('age');
p.$_(p + 10);
alert (bobsKid.dad.age); // shows 43


> However, the `$_object' property (regardless of its name) does not make
> sense except as a marker because its value is a reference to the calling
> object (`this'): this.$_object[this.$_member] === this[this.$_member].  

Good point, don't know how I missed that!

> BTW, there's another potential problem: You try to the augment the instance
> with a property `$_member', a property that becomes enumerable when set,
> and error-prone to rely on when not set.

Ew, missed that too... so that's why I'm not supposed to modify
Object's prototype.

>
> The supposed-to-be type-cast `Object(this)' is also pointless because in
> the context in which it is used, `this' is already a reference to an
> object; or, IOW, `this' *always* refers to an object (for primitive values:
> due to the built-in wrapping object) and does not need to be type-casted
> (provided that was possible so easily).  Incidentally, when the Object()
> function is called as a function or a constructor with an object reference
> as argument, it simply returns that reference without creating a new object
> (ES3/5, 15.2.1.1 and 15.2.2.1).

I read that somewhere too, and originally I just had "return
this;" ... however it doesn't work in Google Chrome (beta 4 at least).
Using the Object() function gives the expected result there. Simply
returning 'this' does seem to work in every other js implementation
I've seen.

>
> > Using this would require rewriting all code, it just requires: (1) wrap
> > primitive in an object so you can use the $_() setter, and (2) use the
> > $_() setter to set a value when you want to modify the value "by
> > reference."
>
> And it would require rewriting of all functions and methods that used the
> wrapper object instead of the primitive value.  Even though they only
> required read access.
>

Wait, why? The wrapper object is treated as a primitive value by
anything that expects a primitive value.

> > Where did I modify constants? Not sure what you mean here either.
>
> `5' is a constant as is `"foo"'.  Constant as in immutable.  One would not
> attempt to modify immutable values, or emulate that by keeping a wrapper
> object to store another value.

Yes, but [5] and ["foo"] are not constants ;) What if you wanted to do
something like this (perfectly valid c++):

##

#include <stdio.h>
void square(int *n) { *n *= *n; }
int main()
{
int i = 5;
square(&i);
printf("%i\n",i); // prints 25
return 0;
}

##

If I try to emulate that by doing something like the following, am I
really trying to modify constants?

##

function square(n) { n._set(n * n); }
function main()
{
int i = [5];
square(i);
alert(i); // prints 25
return 0;
}

##

-- Nick