Closure bug

T

Tim Streater

Ry Nohryb said:
The same example slightly modified can be used to show that it's a
pass-by-reference:

function test (o) { o.j= "Simpson" }
var p= {};
test(p);
p.j
--> "Simpson"

The question is, when you say "it's been passed by reference", what
exactly did you expect *it* to be ?

1.- var p ?
2.- the value of var p (which is a reference to an object) ?

And the answer is in the ES3 specs, 10.1.8, "The initial value (... of
an argument ...) is *the*value* of the corresponding actual parameter
supplied by the caller."

So, while in JS you can't pass a reference to a var, you can't avoid
to pass objects by reference.

You are not passing the object, you are passing a *pointer* to the
object. When you pass this *pointer*, the function makes its own copy of
the *pointer* and the original *pointer* is not modified with the test
function.

Which is why:

function test (o) { o = null; }

does *not* change p, whereas:

function test (o) { o.j= "Simpson"; }

*does* change the *object* that p points at. While test is running,
there are two pointers to the object, and only one before and after (or
at some point after, possibly).
 
R

Ry Nohryb

You are not passing the object, you are passing a *pointer* to the
object. When you pass this *pointer*, the function makes its own copy of
the *pointer* and the original *pointer* is not modified with the test
function.

Which is why:

  function test (o) { o = null; }

does *not* change p, whereas:

  function test (o) { o.j= "Simpson"; }

*does* change the *object* that p points at. While test is running,
there are two pointers to the object, and only one before and after (or
at some point after, possibly).

Exactly. test(p) in JS is exactly as test(&p) in C : a pointer = a
reference.
 
T

Thomas 'PointedEars' Lahn

1. But that is _not_ what happens. This has nothing to do with variables,
as you will see shortly.

You cannot *pass* something (like a reference) to something else that cannot
be called (like a variable). That much is true.

No, you pass the reference value to the function (by value). How many times
has that been explained to you already, Jorge Chamorro, albeit your not
using a pseudonym back then?

/* Firebug 1.5.4: Object { j="Simpson"} */
(function (o) { o.j = "Simpson"; return o; }({}))
You are not passing the object, you are passing a *pointer* to the
object.

No, think twice. If it was a pointer, which it is not, it would work like
call-by-reference: it would be possible to overwrite the object by assigning
to (the identifier of) the argument (since this would require implicit
pointer referencing we could reasonably assume implicit pointer
dereferencing).

Therefore, the term "(object) reference (value)" is being used to describe
what happens instead.


PointedEars
 
R

Ry Nohryb

1.  But that is _not_ what happens.  This has nothing to do with variables,
as you will see shortly.


You cannot *pass* something (like a reference) to something else that cannot
be called (like a variable).  That much is true.


No, you pass the reference value to the function (by value).  How many times
has that been explained to you already, Jorge Chamorro, albeit your not
using a pseudonym back then?

"PointedEars" is to Thomas Lahn what "Ry Nohryb" ( === rot13("El
Abuelo") ) is to Jorge Chamorro: a nick name (not a pseudo-name). My
name is as clear as an unmuddied lake, Fred, as clear as an azure sky
of deepest summer, Fred, you can rely on me, in both in the from
header of my posts and in the signature.
  /* Firebug 1.5.4: Object { j="Simpson"} */
  (function (o) { o.j = "Simpson"; return o; }({}))


No, think twice.  If it was a pointer, which it is not, it would work like
call-by-reference: it would be possible to overwrite the object by assigning
to (the identifier of) the argument (since this would require implicit
pointer referencing we could reasonably assume implicit pointer
dereferencing).

To begin with pointers and C are at a much lower level than JS. In C,
a pointer is a reference to a memory location, and C -being a lower
lever language- allows you to write there whatever you want, and, in
fact, to read what is there and cast it into whatever -any other- data
type you wish, unlike in JS. E.g. you can write a struct (an object)
there and read it back as a char * or a longint, if you wish, or
viceversa.

In JS, the object that the reference points to can be overwritten, and
the reference itself, too, but you can't cast the reference to a
different data type: IOW, given a reference to an object, you can't
make it be a different thing (by casting). And in the same way that a
given memory address (pointer value) always points to the same logical
memory address, a given reference (in JS) can not be made to point to
a different object.

Thinking in terms of pointers, when in C you've got 2 different copies
of the same pointer (pointers in C, as references in JS, are passed by
copy), as when in JS you've got 2 different references to the same
object, assigning a different value to any of the pointers won't
change the other pointer, exactly as what happens in JS.

My point since day 1, is that an object is said to be passed-by-
reference when instead of copying it (as in pass-by-copy), what gets
passed is a *reference* that points to it, as is the case in JS.

You insist in that in JS the reference is a value that gets passed by
copy, and I insist in that that's exactly what C does when passing an
objectOrWhatever by reference as in functionToCall(&objectOrWhatever).

You insist in that that's not to pass by reference, and I insist in
that that's been being called so among C programmers for nearly 3
decades now.
 
R

Ry Nohryb

You insist in that that's not to pass by reference, and I insist in
that that's been being called so among C programmers for nearly 3
decades now.

s/NeArLy/over/ig
 
R

Ry Nohryb

Agreed, that the David Mark example cuts to the chase, and to me this
close cousin example also makes it clear that o is not a reference to p

p is a var whose value is a reference to the object {}.
o is a var whose value is a copy of the value of var p whose value is
a reference to the object {}.
WRT objects, you're always passing references, by copy, but
references, unlike when passing primitive values.
 
R

Richard Cornford

On May 19, 4:45 pm, williamc wrote:
Side note: Zakas refers to non-primitive types as
"Reference Types" in Chapter 5 of his book. This
terminology was objected to by some here,

I don't see why, the terminology is fine, it is just the subject that
it is being applied to that is questionable. The ECMAScript "Reference
type" is the result of evaluating an Identifier and/or a property
accessor (and, theoretically, a possible result of a call to a host
function (though no examples of that actually happening have been
observed)). The act/process of converting a "Reference type" into a
value (the call to the internal GetValue function) may as easily
result in a primitive value as a non-primitive value.
but from reading further in this thread it looks like the
standard also uses that terminology for heuristic purposes,

Which is a very good reason for not applying the term in relation to
javascript in any way that contradicts the standard for javascript.
Doing so is likely to result in misunderstanding and confusion, even
where it does not result from misunderstanding and confusion.
noting that Reference
Types aren't actual ES data types.

That would depend on what you consider a 'data type' in ECMAScript.
The Reference type is an internal type that is used to explain
required behaviour. Implementations do not need to use/implement/
instantiate/etc. such a type so long as they behave as if they did.
However, when talking technically about a language that is entirely
defined in terms of its behaviour it is quite normal to accept the
existence of anything for which an implementation is required to
behave as if it exists.

Richard.
 
R

Richard Cornford

On May 19, 4:54 pm, Ry Nohryb wrote:
WRT objects, you're always passing references, by copy,
but references, unlike when passing primitive values.

How can you tell? Specifically, how can you tall that primitives are
not implemented as structures somewhere in memory and that the values
assigned to object properties/valuables are not references to those
structures; that copying a primitive 'value' from one variable to
another does not actually involve copying a reference?

The thing is that you cannot tell. Javascript offers no operators that
will allow you to modify a primitive, so while you can observe the
modification to an object and conclude that there must be some
'referencing' mechanism that has all values that are objects
'referring' to the single object the inability to do the same test on
the primitives does not excused the possibility that exactly the same
implementation mechanism has been applied to them.

Richard.
 
R

Ry Nohryb

On May 19, 4:54 pm, Ry Nohryb wrote:


How can you tell? Specifically, how can you tall that primitives are
not implemented as structures somewhere in memory and that the values
assigned to object properties/valuables are not references to those
structures; that copying a primitive 'value' from one variable to
another does not actually involve copying a reference?

The thing is that you cannot tell. Javascript offers no operators that
will allow you to modify a primitive, so while you can observe the
modification to an object and conclude that there must be some
'referencing' mechanism that has all values that are objects
'referring' to the single object the inability to do the same test on
the primitives does not excused the possibility that exactly the same
implementation mechanism has been applied to them.

Well, yes, you're right. The observable behaviour must be as if they
were passed by copy, and it is. But then, it's observable as well that
in V8 at least the strings are not passed by copy, because, if you
copy a 100MB string to 8 different vars, V8 does *not* use 800 MB,
even though looking at the specs they should have been duplicated.
It's when you add a single char to them that they are duplicated.
 
T

Thomas 'PointedEars' Lahn

Ry said:
"PointedEars" is to Thomas Lahn what "Ry Nohryb" ( === rot13("El
Abuelo") ) is to Jorge Chamorro: a nick name (not a pseudo-name).

No, I post with my real name, the nick name only in-between. By comparison,
you do not post with your real name, you use your nick name as a pseudonym.
And you know that.
My name is as clear as an unmuddied lake,

It is not, and you know it. Why else would you have changed your From
header?
To begin with pointers and C are at a much lower level than JS.

You are not paying attention. I said *if* that were pointers then what I
describe would happen. I have also said explicitly that they are not, which
makes the rest of your babbling quite irrelevant.
In JS, the object that the reference points to can be overwritten,

No, it cannot. It can only be modified, i.e. it can be augmented with
properties, properties can be deleted, and property values can be changed.
You are not paying attention, for an example that proves that has already
been posted.
My point since day 1, is that an object is said to be passed-by-
reference when instead of copying it (as in pass-by-copy), what gets
passed is a *reference* that points to it, as is the case in JS.

No, that is _not_ how pass-by-reference (better: call-by-reference) is
defined. And therefore call-by-reference simply does not happen in
ECMAScript implementations (to date).


PointedEars
 
R

Ry Nohryb

(idiocies about my nick snipped)

(...)
You are not paying attention.  I said *if* that were pointers then whatI
describe would happen.  I have also said explicitly that they are not, which
makes the rest of your babbling quite irrelevant.

Had you read what I posted, you would know why if that were pointers,
what you describe(d) is not what would happen.
No, it cannot.  It can only be modified, i.e. it can be augmented with
properties, properties can be deleted, and property values can be changed..  
You are not paying attention, for an example that proves that has already
been posted.

You are not paying attention: of course the object that it refers to
can be completely overwritten.

And you're misunderstanding this: when you have a reference that
points to object A and want it to point to object B, its value must
change, but that won't change automagically any other copies of the
reference to object A in existence, but that does not make it any less
of a reference.
No, that is _not_ how pass-by-reference (better: call-by-reference) is
defined.  And therefore call-by-reference simply does not happen in
ECMAScript implementations (to date).

You can repeat that as many times as you want, but in JS objects are
passed by reference exactly as in C. It's just that most script-
kiddies are too young -and lacking in C- to comprehend it.
 
R

Ry Nohryb

(...) If it was a pointer, which it is not, it would work like
call-by-reference (...)

That's not true either. Not in C. To begin with, there's no such thing
as "call by reference" in C. But there's "pass by reference", as in
JS. See:

http://google.com/search?q=pass+by+reference+in+C

The very first link would do:
http://publib.boulder.ibm.com/infoc.../com.ibm.xlcpp8a.doc/language/ref/cplr233.htm

Note, however, that in C, there's a way to avoid the need to apply the
& operator to the object in order to get it passed by reference (as in
JS), so, instead of the usual:

$cat a.c
#include <stdio.h>
typedef struct objeto { int aProperty; } tipo;
void test (tipo* o) { o->aProperty = 27; }
int main (void) {
tipo o;
test(&o);
printf ("%d\n", o.aProperty);
return 0;
}

$ gcc a.c
$ ./a.out
--> 27

The call can be written as test(o) [ NOTE: that looks exactly like JS,
yet more funny: it BEHAVES exactly like JS ] just by declaring the
struct as a one element array of structs:

$ cat b.c
#include <stdio.h>
typedef struct objeto { int aProperty; } tipo [1];
void test (tipo o) { o->aProperty = 27; }
int main (void) {
tipo o;
test(o);
printf ("%d\n", o->aProperty);
return 0;
}
$ gcc b.c
$ ./b.out
--> 27
 
R

RobG

RobG said:
Thomas said:
RobG wrote:
[...]
[...]
I think in both cases their values are references because, to me, it
is less confusing. As I posted eariler, given:
var a = 5,
b = a;
You can think of a and b as refering to the same instance of 5.
But you should not. While Smalltalk undoubtedly is an ancestor of
JavaScript/ECMAScript, by contrast `5' is _not_ an object in ECMAScript
implementations (it is only being implicitly converted to a Number
instance sometimes).
So, in your words, `b' "refers" to _another_ `5' than `a'.
No, in my words, 'b' and 'a' refer to the same '5'. Since that '5'
can't be modified, the value of 'b' can only be changed by assigning a
new value, even if it's another '5'.

That's nonsense. Have you subscribed to VK101 by now?

There is no imperative to copy the value to b. The value '5' can't be
modified, so there is no chance that assigning a new value to a will
result in a change of the value of b. It seems an implementation may,
in the interests of efficiency, make a and b the same primitive.

I tried Jorge's VB test in IE and Firefox (code below). One function
created 1,000 global variables with the same 375KB of text assigned to
each. A second function assigned a unique string to each by slightly
modifying its original string. Results were:

In IE 6:

Start: 609MB
Load page in new instance of IE: 617MB
Create 1,000 variables: 1,367MB
Modify them: 1,367MB

In Firefox 3.6
Start: 612MB
Load page in new tab: 615MB
Create 1,000 variables: 617MB
Modify them: 1,380MB

I think the above shows that IE creates 1,000 copies if the same
string initially, consuming about an extra 650MB of memory. Assigning
new values of the same size doesn't use any extra memory. However,
Firefox's much lower initial memory use indicates that it creates
1,000 references to the same string. It is only when a new string is
assigned to each variable that it creates 1,000 separate strings and
consumes and extra 760MB or so of memory.

No, implementation details are at the core of the issue.

So if implementation details matter (and you seem to think they do),
then you can argue on a per implementation basis as to whether my
original example above (var a=5, b=a; etc.) results in a reference to
the same primitive or a new copy being created.

I don't think implementation details matter, my opinion is purely a
theoretical exercise to create a system for understanding behaviour
that is consistent with the specification and observation. My idea of
"references" to primitives seems to fit with Firefox, your idea of
each assignment creating a new copy, always, fits with IE.

I might have a Message-ID.

I would appreciate it if you can find it.


Test code:

<script type="text/javascript">

// Text seed
var txt = "..."; // Slab of text, say 3,500 characters

// bigTxt will be about 100 times bigger than txt
var bigTxt = (function() {
for (var i=100, s=''; i; i--) {
s += txt;
}
return s;
})();

// Create a bunch of global vars, assign bigTxt
function createVars() {
for (var i=1000; i; i--) {
window['a' + i] = bigTxt;
}
};

// Modify created globals
function modifyVars() {
for (var i=1000, t; i; i--) {
t = window['a' + i]
window['a' + i] = i + ' ' + t;
}
}
</script>

<button onclick="alert(a1);">Show a1</button>
<button onclick="createVars()">Create vars</button>
<button onclick="modifyVars()">Modify vars</button>
 
L

Lasse Reichstein Nielsen

Ry Nohryb said:
On May 19, 10:35 pm, Thomas 'PointedEars' Lahn <[email protected]>
wrote:

You can repeat that as many times as you want, but in JS objects are
passed by reference exactly as in C. It's just that most script-
kiddies are too young -and lacking in C- to comprehend it.


C is a bad example since it doesn't have reference parameters at all
(nor objects, for that matter).

The behavior in javascript does match the passing of an object
reference in C++. However, you can't pass a variable in javascript,
only an object reference, which is why it isn't what is traditionally
considered call-by-reference.

It's just that objects aren't denotable values in Javascript, nor
expressible cvalues for that matter, only object references are.

/L
 
R

Ry Nohryb

(...)
So from this viewpoint, Ry Nohryb is right. That exactly how JS works
and it can be compared with C's pointers (but with one important
difference -- it is impossible to dereference this pointer and change
the value to which it points). (...)

No, neither in C: as I tried to explain to Pointy, in C you would
*not* be able to "change the value to which it points" without
resorting to type casting: IOW: exactly as in JS: a reference to an
object can't be made to point to e.g. an array or a number. But type
casting is a different feature that belongs to a separate chapter.
 
D

Dmitry A. Soshnikov

No, neither in C: as I tried to explain to Pointy, in C you would
*not* be able to "change the value to which it points" without
resorting to type casting: IOW: exactly as in JS: a reference to an
object can't be made to point to e.g. an array or a number. But type
casting is a different feature that belongs to a separate chapter.


Wait the second, how a type casting is relevant with that we can
dereference a pointer (of our type of course - a structure in the
example below) and assign a new value for the memory block?

I.e.:

#include <stdio.h>

struct Object {
int x;
int y;
};

void foo(struct Object* oRefCopy)
{

struct Object o2;
o2.x = 100;
o2.y = 200;

*oRefCopy = o2;
}

int main()
{
struct Object o;

o.x = 10;
o.y = 20;

foo(&o);

printf("o.x = %d, o.y = %d", o.x, o.y); // 100, 200

return 0;
}

Dmitry.
 
R

Richard Cornford

Well, yes, you're right. The observable behaviour must be
as if they were passed by copy,

I would have to disagree with that. The specified behaviour does not
include anything that you could observe in order to make the
differentiation.
and it is.

Doesn't your following observation show that "is" should be replaced
by "may or may not be"?
But then, it's observable as well that in V8 at least
the strings are not passed by copy, because, if you copy

How do you "copy" a string in javascript? You can assign a string
primitive values that is already assigned to some property/variable to
another property/variable but that only results in two properties/
variables having the same "value".
a 100MB string to 8
different vars, V8 does *not* use 800 MB,

Fine, there is no reason why it should.
even though
looking at the specs they should have been duplicated.

That has never been my reading of the spec. When a specification is
couched in terms of required behaviour, if there should be a copy then
there should also be some means of observing that there was a copy
(from within the language).
It's when you add a single char to them that they are
duplicated.

You cannot "add a single char" to a string primitive value, because
the language does not include any operators, methods or syntax that
are capable of modifying primitive values. An expression such as - st
+= 'x'; -(assuming st to have a value that is a string primitive) does
not modify the value held by st, it replaces it with a new value that
is the string primitive containing all the characters that were in the
string that was the value of st with an 'x' value concatenated to the
end. This is the creation of a new string primitive not a modification
to an existing one. Increased memory use would be difficult to avoid
when new values are being created.

Richard.
 
R

Ry Nohryb

Wait the second, how a type casting is relevant with that we can
dereference a pointer (of our type of course - a structure in the
example below) and assign a new value for the memory block?

I.e.:

#include <stdio.h>

struct Object {
int x;
int y;

};

void foo (struct Object* oRefCopy) {
struct Object o2;
o2.x = 100;
o2.y = 200;
*oRefCopy = o2;
}

int main (void) {
struct Object o;
o.x = 10;
o.y = 20;
foo(&o);
printf("o.x = %d, o.y = %d", o.x, o.y); // 100, 200
return 0;
}

Well, that does not illustrate a way to assign anything "different"
because both objects are of exactly the same type and therefore what
you're doing here is just a convoluted (and inefficient, btw) way of
doing this:

void foo (struct Object* oRefCopy) {
oRefCopy->x = 100;
oRefCopy->y = 200;
}

And, unless you resort to type casting, you *won't* be able put
anything other (different) than exactly an "Object" type into o, just
as happens in JS: a reference to an object (in JS) will always point
to that object: you can modify it, but you can't make it be anything !
== than the object that it is.
 

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
474,078
Messages
2,570,570
Members
47,204
Latest member
MalorieSte

Latest Threads

Top