Passing primitive variables by reference in JavaScript

T

Thomas 'PointedEars' Lahn

nick said:
A few weeks ago I cooked up this solution for passing primitive
variables by reference in JavaScript (or emulating it, at least) and
I'd like to get some feedback from the pros... Check out this blog
post:

http://codetoss.blogspot.com/2009/12/passing-variables-by-reference
in.html

...Is this a good idea? Good implementation? Why or why not? Looking
forward to your feedback :)

It is madness.

- $-prefixed property names are a problem for many reasons; avoid them
as recommended by Edition 3 Final of the (ECMAScript) Specification.
- You want to avoid augmenting Object.prototype.
- Objects have identity, not 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.
- Assignment to undeclared `v' (and `foo') makes it globally available,
overwrites a property in the scope chain or causes a runtime error.
- toString() should return a primitive string value.
- The modification does not work transparently; all code would
need to be rewritten -- to be considerably less efficient afterwards.
- Concept error: Nobody sane would not want to *modify* *constants*.

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.

You want to post some code next time. We are _not_ on the Web here.


PointedEars
 
N

nick

It is madness.

- $-prefixed property names are a problem for many reasons; avoid them
  as recommended by Edition 3 Final of the (ECMAScript) Specification.
- You want to avoid augmenting Object.prototype.
- Objects have identity, not 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.
- Assignment to undeclared `v' (and `foo') makes it globally available,
  overwrites a property in the scope chain or causes a runtime error.
- toString() should return a primitive string value.
- The modification does not work transparently; all code would
  need to be rewritten -- to be considerably less efficient afterwards.
- Concept error: Nobody sane would not want to *modify* *constants*.

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.

You want to post some code next time.  We are _not_ on the Web here.

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.)

I apologize for not posting the code here... for reference, the
original snippet looked like this:

##

// 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.
- $-prefixed property names are a problem for many reasons; avoid them
  as recommended by Edition 3 Final of the (ECMAScript) Specification.

Ok, easy enough.
- 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');
foo.$_('red'); // background of page turns red
document.body.style.backgroundcolor = 'black';
// value of foo is now 'black'
- 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.
- 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.
- Assignment to undeclared `v' (and `foo') makes it globally available,
  overwrites a property in the scope chain or causes a runtime error.

A simple omission; forgot to type 'var'.
- 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?
- 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, as the language doesn't
support any concept of pointers? 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."
- Concept error: Nobody sane would not want to *modify* *constants*.

Where did I modify constants? Not sure what you mean here either.

Here's a modified snippet....

##

// 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);
function v() { return this._object_[this._member_].valueOf(); };
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
{
var v = value.valueOf();
this.valueOf = this.toString = function() { return v; };
}
return this;
};

##

....does that look any better?

-- Nick
 
N

nick

On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <[email protected]>
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
 
T

Thomas 'PointedEars' Lahn

nick said:
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?
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.
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).
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.
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.
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
 
N

nick

On Jan 17, 10:24 am, Thomas 'PointedEars' Lahn <[email protected]>
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 ;)
 
N

nick

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...
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.
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.
`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
 
T

Thomas 'PointedEars' Lahn

nick said:
| 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?

Your code is not mechanically generated, is it?

AIUI, the reference to "mechanically generated" here is threefold:

a) Code being generated by other code (e.g., server-side PHP generates
ECMAScript-compliant code; to use `$' for a normal property would
make the generating code harder to write and to read as variable
references must start with `$' in, e.g., PHP).

b) Built-in properties like $`; user-defined properties should be
easily distinguishable from those.

c) Host environments can augment native objects with properties;
user-defined properties should be easily distinguishable from those.


PointedEars
 
T

Thomas 'PointedEars' Lahn

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

As I said, bad inference.
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);

Eeek. Compare that against

bobsDad.son.age += 10;
alert (bobsKid.dad.age); // shows 43

You are really not making a good case here.
I read that somewhere too, and originally I just had "return
this;" ... however it doesn't work in Google Chrome (beta 4 at least).

Someone please file a bug after checking the released version.
Using the Object() function gives the expected result there. Simply
returning 'this' does seem to work in every other js implementation
I've seen.

You probably mean "every other *ECMAScript* implementation"
(Netscape/Mozilla.org JavaScript is one).
Wait, why? The wrapper object is treated as a primitive value by
anything that expects a primitive value.

I stand corrected. Your example (`num.$_(num * num)') confused me. Still,
obviously it would require rewriting all functions and methods that attempt
to set the value.
`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 ;)

So what? If this was to be used on proper objects (like the Array
instances here), it would have proven its own unnecessity. [5][0] === 5,
["foo"][0] === "foo".
What if you wanted to do something like this (perfectly valid c++):

You don't. ECMAScript is not C++, Java is not PHP, Perl is not Python.
Anyhow, no offense meant, but this code looks more like one from a C
developer that failed to evolve from the need of direct memory manipulation
than proper 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;

This is even poor code quality by C standards. Pray tell, what is
advantage of referring to a variable by reference only to discard it later?
Is it not instead that the reference and ultimately the variable was
unnecessary in the first place, that the function should have returned the
proper value instead, as in

int i = 5;
printf("%i\n", i * i);

or

printf("%i\n", square(i));

or

printf("%i\n", square(5));

or, $DEITY forbid,

printf("%i\n", 5 * 5);

or even

printf("25\n");

?
^^
Please do not do that. Use unambiguous delimiters like `---' or indent
your code instead.
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];

What is this supposed to mean? (An Array instance that is a primitive
integer -- a contradiction?)
square(i);

In object-oriented programming, we have managed to move on beyond the
context-less functions of the plain procedural programming paradigm that
spoil the global namespace; instead, we try to associate functions with the
data they are supposed to operate on, by which they become methods of the
target object and work like (and sometimes are implemented as) messages to
that object:

i.square = function() {
for (var i = this.length; i--;)
{
var v = this;
this = v * v;
}
};

/* "square" `i' */
i.square();

Not that a method would be necessary here:

for (var j = i.length; j--;)
{
var v = i[j];
i[j] = v * v;
}

(Kids, don't try this at home! `i' should be reserved for counters.)

But it might come in handy.


PointedEars
 
N

nick

Eeek.  Compare that against

  bobsDad.son.age += 10;


You are really not making a good case here.

The point I was trying to make was I am not "assuming that an object
can only ever be referred to by the same property" ... I'm assuming it
doesn't matter. Can you think of an example where this would be a
problem?
Yes, but [5] and ["foo"] are not constants ;)

So what?  If this was to be used on proper objects (like the Array
instances here), it would have proven its own unnecessity.  [5][0] === 5,
["foo"][0] === "foo".

What? Regular objects are already passed by reference, I'm not worried
about that. I want to reference primitive types.
[...]
#include <stdio.h>
void square(int *n) { *n *= *n; }
int main()
{
  int i = 5;
  square(&i);
  printf("%i\n",i); // prints 25
  return 0;

This is even poor code quality by C standards.  Pray tell, what is
advantage of referring to a variable by reference only to discard it later?  
Is it not instead that the reference and ultimately the variable was
unnecessary in the first place, that the function should have returned the
proper value instead, as in

  int i = 5;
  printf("%i\n", i * i);

or

  printf("%i\n", square(i));

or

  printf("%i\n", square(5));

or, $DEITY forbid,

  printf("%i\n", 5 * 5);

or even

  printf("25\n");

?

It's just example code that I typed up in 5 seconds, the point is that
I'm passing integers by reference. Obviously there is no "advantage"
to anything I did in this scenario... it's just a simple example.
  ^^
Please do not do that.  Use unambiguous delimiters like `---' or indent
your code instead.

Whatever makes you happy.

`---'
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];

What is this supposed to mean?  (An Array instance that is a primitive
integer -- a contradiction?)

`---'

The [5] notation is just for wrapping a primitive in an an object,
like Object(5).

`---'
In object-oriented programming, we have managed to move on beyond the
context-less functions of the plain procedural programming paradigm that
spoil the global namespace; instead, we try to associate functions with the
data they are supposed to operate on, by which they become methods of the
target object and work like (and sometimes are implemented as) messages to
that object:
...
(Kids, don't try this at home!  `i' should be reserved for counters.)

`---'

Look, I don't need a lecture on object-oriented programming (js not
being an OO language last time I checked anyway). There is plenty of C+
+ code around where classes have methods that pass and receive
pointers to ints and doubles all over the place... FLTK comes to mind.
Whether or not you think passing primitive types by reference in an OO
language is a good idea, it's useful, it's fast and it works. /OT

Whether or not that translates to *ECMAScript* I can't say, but it is
at least a fun learning experiment :)

-- Nick
 
T

Thomas 'PointedEars' Lahn

nick said:
The point I was trying to make was I am not "assuming that an object
can only ever be referred to by the same property" ... I'm assuming it
doesn't matter. Can you think of an example where this would be a
problem?

The `$' aside? Perhaps. I need to think about it, later.
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 ;)

So what? If this was to be used on proper objects (like the Array
instances here), it would have proven its own unnecessity. [5][0] ===
5, ["foo"][0] === "foo".

What? Regular objects are already passed by reference,

No, objects are not passed at all. Object *references*, which are values,
are passed by value, like everything else.
I'm not worried about that. I want to reference primitive types.

Do not use proper objects as examples to make a point, then.
[...]
#include <stdio.h>
void square(int *n) { *n *= *n; }
int main()
{
int i = 5;
square(&i);
printf("%i\n",i); // prints 25
return 0;

This is even poor code quality by C standards. Pray tell, what is
advantage of referring to a variable by reference only to discard it
later? Is it not instead that the reference and ultimately the variable
was unnecessary in the first place, that the function should have
returned the proper value instead, as in [counter-examples]?

It's just example code that I typed up in 5 seconds, the point is that
I'm passing integers by reference. Obviously there is no "advantage"
to anything I did in this scenario... it's just a simple example.

A simple example that shows why this approach does not make sense, that it
is the result of a misconception.
Whatever makes you happy.

`---'

First of all, this is not about me. Second, the <`> and <'> only delimit
the suggested string of characters, of course. Third, it was supposed to
delimit source code from comments, not everything from each other. This is
Usenet; learn to post.

[snipped bogus delimiters]
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];

What is this supposed to mean? (An Array instance that is a primitive
integer -- a contradiction?)

The [5] notation is just for wrapping a primitive in an an object,
like Object(5).

Object(5) is unnecessary, though. Wrapper objects that have the
corresponding prototype objects in their prototype chain are created
automatically whenever primitive convertible values are used with property
accessors.
square(i);

In object-oriented programming, we have managed to move on beyond the
context-less functions of the plain procedural programming paradigm that
spoil the global namespace; instead, we try to associate functions with
the data they are supposed to operate on, by which they become methods
of the target object and work like (and sometimes are implemented as)
messages to that object: [...]

Look, I don't need a lecture on object-oriented programming

Quite obviously you do.
(js not being an OO language last time I checked anyway).

Check again.
Whether or not that translates to ECMAScript I can't say, but it is
at least a fun learning experiment :)

Undoubtedly. However, I do not think you have learned all the right
lessons from it (yet).


PointedEars
 
N

nick

nick wrote:
...

No, objects are not passed at all.  Object *references*, which are values,
are passed by value, like everything else.

Semantics. I think my meaning was clear.
Object(5) is unnecessary, though.  Wrapper objects that have the
corresponding prototype objects in their prototype chain are created
automatically whenever primitive convertible values are used with property
accessors.

Right, but writing "var foo=5;" is not the same as "var foo=Object
(5);"
In other words, "var foo=5" is like "var foo=Number(5)", while
"var foo=Object(5);" acts like "var foo=new Number(5);" would... even
though both get automatically wrapped by a wrapper object, in the
first case foo is assigned the primitive value, instead of the
reference to the wrapper object. In other words the automatic wrappers
seem "temporary," while objects created with {}, [], Object(), seem to
"stick around." I'm sure that is horribly semantically incorrect,
though.

Look:

---

// Set the value of current object.
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 x = 5;
square(x);
alert(x); // gives 5 -- no good

var y = new Number(5);
square(y);
alert(y); // gives 25 -- yay

var z = Object(5);
square(z);
alert(z); // gives 25 -- this works too

---

Quite obviously you do.

Excuse me but I can't imagine why you think that. Is it because my 5-
line example code has no real world use, or because you really think
references to primitive types have no place in OO programming? Either
way, I'll try to give a better example.

In a UI toolkit, a spinner control class has a property called
"Value." Value is a pointer to an int. Another class (call it Box) has
two properties, Top and Left, both pointers to ints. During the
display routine, Box will draw itself according to Top and Left. The
spinner control will show "Value" in a text box.

Now, say vSpinner.Value and myBox.Top point at the same int, and
hSpinner.Value and myBox.Left point at the same value... and lets say
you can drag Box around, which will modify its Top and Left
properties. Spinning the spinners will now move the box, moving the
box will update the spinners, and everything is kept in sync. There
you have it, useful pointers to primitive types in OOP. I hope that
example helps?

-- Nick
 
L

Lasse Reichstein Nielsen

nick said:
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.

All this work, and we are back at the good old hack of wrapping
primitives as unit-arrays to pass them by "reference".
(I've used it in Java too, and it's still a hack).

/L
 
J

Jorge

In a UI toolkit, a spinner control class has a property called
"Value." Value is a pointer to an int. Another class (call it Box) has
two properties, Top and Left, both pointers to ints. During the
display routine, Box will draw itself according to Top and Left. The
spinner control will show "Value" in a text box.

Now, say vSpinner.Value and myBox.Top point at the same int, and
hSpinner.Value and myBox.Left point at the same value... and lets say
you can drag Box around, which will modify its Top and Left
properties. Spinning the spinners will now move the box, moving the
box will update the spinners, and everything is kept in sync. There
you have it, useful pointers to primitive types in OOP. I hope that
example helps?

Yep. That or just make the reference to the primitive visible -in
scope- of course... but if you insist, I have this idea:

Object.prototype.setValueOf= function (p) {
this.valueOf= function () {return p;};
return this;
};

a={}.setValueOf(27)
--> Object
a+a
--> 54
a.setValueOf(5)
--> Object
a*a
--> 25
a.setValueOf(a*10)
--> Object
a+a
--> 100
a.setValueOf("wow ")
--> Object
a+a
--> "wow wow "

:)
 
T

Thomas 'PointedEars' Lahn

nick said:
Semantics.

No. Pass-by-reference (call-by-reference) is not the same as pass-by-value
(call-by-value). (Object) references are _values_ in these languages.
I think my meaning was clear.

Evidently it was not.
Right, but writing "var foo=5;" is not the same as "var foo=Object
(5);"

It is the same as

var foo = new Number(5);

if and when `foo' is later used in a /MemberExpression/.
In other words, "var foo=5" is like "var foo=Number(5)",
No.

while "var foo=Object(5);" acts like "var foo=new Number(5);" would...
No.

even though both get automatically wrapped by a wrapper object, in the
first case foo is assigned the primitive value, instead of the
reference to the wrapper object. In other words the automatic wrappers
seem "temporary," while objects created with {}, [], Object(), seem to
"stick around." I'm sure that is horribly semantically incorrect,
though.

It is completely wrong.

That is why you should make use of the prototype chain, but not augment
Object.prototype.
Look:

---

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

What a nonsense.
return this;
};

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

var x = 5;
square(x);
alert(x); // gives 5 -- no good

You still miss the point. `square' is _not_ a method of the wrapper object
of `5'; that is its major flaw.
var y = new Number(5);
square(y);
alert(y); // gives 25 -- yay

Nobody said you should do that. In fact, it is strongly recommended
against.
var z = Object(5);
square(z);
alert(z); // gives 25 -- this works too

This is strongly recommended against either.
Excuse me but I can't imagine why you think that. Is it because my 5-
line example code has no real world use, or because you really think
references to primitive types have no place in OO programming?

It is because you are still using a context-less (global) function to
operate on a primitive value that you wrap into an object instead of using
the wrapper object automatically created if you call a function as method
of this object.
Either way, I'll try to give a better example.
In a UI toolkit, a spinner control class has a property called
"Value." Value is a pointer to an int.

No, it is not.
Another class (call it Box) has
two properties, Top and Left, both pointers to ints.

No, they are not. Apparently you did not understand pointers either.
During the display routine, Box will draw itself according to Top and
Left. The spinner control will show "Value" in a text box.

Now, say vSpinner.Value and myBox.Top point at the same int,

Nothing points to an int. Same value does not mean same memory location.
and hSpinner.Value and myBox.Left point at the same value...

This is rather insane application design. Either one property is
superfluous or it should have a getter that retrieves the other
property's value.
and lets say you can drag Box around, which will modify its Top and Left
properties. Spinning the spinners will now move the box, moving the
box will update the spinners, and everything is kept in sync. There
you have it, useful pointers to primitive types in OOP. I hope that
example helps?

No, your example is bogus. The primitive value that the property holds can
be easily modified with modifying the property value directly, with user-
defined setters of *the object that is the owner of the property*. That
is, the method that modifies the property value should _not_ be a method of
the value but of *the object that has it as a property*.

For it is the object (here: the spinner box) that needs to be updated in
the process, not only the property value. And it is the object that needs
to provide information as to its status and _not_ its property, so as to
hide implementation details. Because accessing implementation details
would prevent the object from being modified without the need to modify the
code that uses it.

Encapsulation and information hiding are two of the core principles of
object-oriented programming, and you have violated both in the process.


PointedEars
 
S

Scott Sauyet

No, it is not.

How could you *possibly* know the implementation of Nick's imaginary
toolkit? It's easy enough to imagine a C++ toolkit that included this
code:

int *Value

Is there something intrinsic to UI toolkits that you think disallows
such an implementation? Or do you think that since it can't be done
directly in ECMAScript it can't be done anywhere? Remember that the
whole point of this thread was of possible ways to do exactly this in
ECMAScript?

No, they are not.  Apparently you did not understand pointers either.


Since Nick is postulating his own toolkit, and workable implementation
of his ideas are easily conceivable, how can you conclude that he
doesn't understand pointers?

Nothing points to an int.  Same value does not mean same memory location.

In any language?

This is rather insane application design.  Either one property is
superfluous or it should have a getter that retrieves the other
property's value.

Not if you need to be able to use spinners and boxes independently of
one another. Why not a Spinner class that takes an int pointer in one
of its constructors? It could be used like this:

Spinner vSpinner = new Spinner(myBox.Top);

What is fundamentally wrong with this?

No, your example is bogus.  The primitive value that the property holdscan
be easily modified with modifying the property value directly, with user-
defined setters of *the object that is the owner of the property*.  That
is, the method that modifies the property value should _not_ be a method of
the value but of *the object that has it as a property*.

What do you mean by "bogus"? Do you simply think that this is a poor
design that a programmer should not implement, or that it is so
egregious that the language should not support it?

C++ certainly supports this pattern. In Java, there is no direct
equivalent, as you'd have to create small mutable wrapper objects
rather than primitives; they'd be much more burdensome to use. There
was good reason not to include any simple pointers in Java, but there
are also good reasons to use them in C++, always bearing in mind that
with great power comes great responsibility.

But if you are arguing a matter of programming taste, perhaps your
tone should be somewhat less peremptory. BTW, my day-to-day language
is Java; I'm used to these restrictions. In fact, I agree that this
design would be less than ideal, to say the least. But that does not
mean that the OP doesn't have a reason to pursue the question at hand.

-- Scott
 
T

Thomas 'PointedEars' Lahn

Scott said:
In any language?

You know what I mean.
Not if you need to be able to use spinners and boxes independently of
one another. Why not a Spinner class that takes an int pointer in one
of its constructors? It could be used like this:

Spinner vSpinner = new Spinner(myBox.Top);

What is fundamentally wrong with this?

Nothing. You miss the point.
What do you mean by "bogus"? Do you simply think that this is a poor
design that a programmer should not implement, or that it is so
egregious that the language should not support it?

It is poor design, to say the least.
C++ certainly supports this pattern.

A burning match supports that you hold it right below your hand.
[...]
But if you are arguing a matter of programming taste,

I am not. I have made my argument, now you only need to recognize it.
perhaps your tone should be somewhat less peremptory.

Perhaps you should talk less and read more.


PointedEars
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

Forum statistics

Threads
473,731
Messages
2,569,432
Members
44,832
Latest member
GlennSmall

Latest Threads

Top