D
Dmitry A. Soshnikov
Hi Dmitry,
Hi Jorge (aka Ry Nohryb),
1.- In the section "General Theory" you could as well say that the
order in which the arguments are evaluated in well specified in ES
(unlike in other languages, notably, C), it is from left to right.
This is of great importance if you happen to code something like this:
foo(a++, a+b);
Yep, fair enough. But it doesn't relate much to exactly passing from
the outside strategy. More, it e.g. can differ in evaluation if-
conditions. But it depends also on complier version. E.g. in MS studio
2005 I have the same result for evaluation this code -- both (C++ and
SpiderMonkey) evaluate it from left to right:
// JS
function testFn(a, b) {
alert([a, b])
}
var a = 10;
var b = 20;
testFn(a++, a + b); // 10, 31
// C++, MS studio 2005 compiler
void testFn(int a, int b)
{
cout << a << ", " << b;
}
int a = 10;
int b = 20;
testFn(a++, a + b); // 10, 31
I guess you've expected to see 11, 31? Then, in both (discussing)
languages we should use prefix-increment operation:
testFn(++a, a + b);
That's it.
2.- Pass-by-xxx and call-by-xxx can be used interchangeably. I would
stick to one of them. In the "Introduction" you use the term passed by
but in the sections you use call by. I for one would prefer "pass by"
everywhere as it's used more commonly than "call by", and I find it
more intuitive.
Yes, also true. Other descriptions use "call-by-xxx". So in my article
I (for this particular case) I make this terms equal, meaning that it
is possible to name with this and that term. If to use only "pass-by-
xxx", readers can be confused when will find similar description but
with "call-by-xxx" terminology. But yea, in everyday discussions we
usually use "pass-by-xxx".
3.- Wrt the behaviour described in "Call by reference", let me tell
you that the behaviour when passing by reference an object in C is
exactly the same as in ECMAScript [*1].
No, actually, no. I'll show an example below.
C's behaviour has always been
called pass by reference, even though the reference is passed by
value. E.g. the wikipedia article about this says : "Even among
languages that don't exactly support call-by-reference, many,
including C and ML, support explicit references (objects that refer to
other objects), such as pointers (objects representing the memory
addresses of other objects), and these can be used to effect or
simulate call-by-reference (but with the complication that a
function's caller must explicitly generate the reference to supply as
an argument).". I would add, "and with the complication that the
pointer has to be dereferenced explicitly in order to access the
object".
Well, C/C++ has call-by-reference "sugar". And in this case formal
parameter will be direct alias of the object from the outside. It
doesn't require dereferencing operation. And assigning to the
reference -- change object completely, but not assign this name to the
new address as it would be in case of by-pointer/by-sharing.
4.- "Call by sharing" would be the best way to call it, were it not
for the fact that the semantics it describes get different names
depending on where you come from, some call it pass-by-reference and
some call it pass-by-value, because in fact it's both of them at the
same time: it's a "call-by-value, where the value is implied to be a
reference to the object". Exactly what C does, and what we've been
calling to pass by reference for ~ 4 decades.
Yes, but let me remind, that my articles mostly theoretical. And the
main objective of this chapter 8 is to show where the roots of these
evaluation strategies.
Regarding C/C++ (but regardless, that its implementation is just "one
of") -- yeah, we say that we deal with reference in both case: with
passing by pointer and with passing by reference. Moreover, as I
mentioned above, by-reference -- is just a syntactic sugar which is
useful in case when we want to affect object of the caller inside the
function but without using dereferencing operation.
void foo(int &bar) {
bar = 20; // it is not a pointer, but reference -- an alias
}
int x = 10;
foo(x); // pass by reference
cout << x; // 20
But, as it is a sugar, it's the same as:
void foo(int *bar) {
*bar = 20; // it is a pointer, not reference
}
int x = 10;
foo(&x); // by pointer value - address
cout << x; // 20
5.- In "Terminology versions" you say
<quote>
The statement "objects are passed in function by reference" formally
is not related with ECMAScript and is incorrect.
</quote>
It is not anymore incorrect than saying that "in C objects can be
passed by reference" or "in Ruby objects are passed by reference" or
"in Java objects are passed by value, where the value is a reference".
In C it is possible to pass by-reference and by-pointer. In both cases
it is possible to say: "we deal with the address, with the reference".
But semantics of that strategies differ. Assigning in first -- changes
the value of the outside object, assigning in second -- binds it to
the new address (but assigning with dereferencing -- also changes the
value).
I think that this matter is turning into a kind of holy war. If I were
to write on this matter, I would avoid any attempt to force a
terminology for as you should see there are good reasons for using any
of them, and different people coming from different languages are used
to call it differently, and none of them is wrong.
Yes, as I said, the main purpose of the theoretical article is to
clarify deeply some aspects (including terminological). It is not
about everyday speaking where we can say that object is passed by
reference (meaning that we can change it's properties inside the
function).
But often (very often) there are questions on forums like the "wtf,
why can't I change object inside the function? I read - it passed by
reference!", and then we see the code:
function foo(bar) {
bar = {x: 20}
}
var bar = {x: 10};
foo(bar);
"Why the heck bar still has {x: 10} ?"
alert(bar.x); // 10
I saw similar question many times on forums. Please notice, in case of
C++ by-reference we would have {x: 20}. But in case of C++ by-pointer
(which is by-sharing) -- would not (excluding dereferencing, i.e. a
"safe pointer").
[*1] If you're interested, I can provide you an example that proves
this point. What you say in "By sharing and pointers" :
<quote>
Regarding ó/ó++, this strategy is ideologically similar to passing by
pointer values, but with one important difference -- that it is
possible to dereference the pointer and to change the object
completely.
</quote>
is wrong.
No, it is correct. See example below.
In C, an argument that is a pointer is a copy of a
reference, just as an argument that is a reference in ES. When a
function receives an argument that is a pointer, it can either change
the argument's value alltogether and make it point to somewhere/
something else (in ES that would be the equivalent of assigning a
completely different value to the argument, as in reference= {}, or
reference= "fjh", or reference= 27, or reference= null, or reference=
youNameIt) or touch the contents of the object that the pointer points
to using a dereferencing operator, either pointer->property= value or
(*pointer).property= value, exactly as you'd do in ES, the only
difference being that in ES there's no need to dereference explicitly:
reference.property= value would do.
That's exactly I wrote -- but in case of a *pointer*, not the
*reference*. I repeat, regardless that reference-concept is just a
sugar for the pointer in C++, and regardless that in both cases we
have a "reference is an address" definition.
There's *nothing* that can be done
in C when passing an object by reference (as in f(&object) ),
If this is a function definition (or prototype), then it is a
"reference" (then call of this "f" function would be just f(object),
when object will be an "alias"). If f(&object) is already a call, then
it is a by-pointer, i.e. address *value*. It is the very subtle
difference, but nevertheless is a difference.
that
can't be done in ES. Their behaviours are identical.
Yes, there is. In ES we can't change object of the caller completely
assigning a new value to it (as we can in C++ in case of by-reference
strategy).
And again. This
behaviour has been called "to pass by reference" for decades.
There are exact distinctions between "by-value", "by-reference" and
"by-pointer"/"by-sharing". Again, my article is mostly about theory,
but not just about everyday talks when we can omit this deep analysis
and name it as "by-reference" but -- only meaning that we can change
object's properties but not the object itself.
Moreover, as I wrote, if to consider only abstraction level provided
by ECMA-262-3, then in every algorithm we see concept of a "value".
And discussing from this viewpoint (from this level of abstraction) we
can not even to think about that "reference", "not-a-reference",
"pointer" and so on. But. Of course, if we want to understand it
deeply, then we should consider the implementation level, where we see
pass by a safe pointer or (in the theory) -- by sharing.
And "sharing" (which is named by Liskov) is when several binding names
can be bound to the same memory block (to the same memory address). Is
it so in ES? Absolutely:
var foo = {x: 10};
bar = foo;
baz = bar;
// etc.
So this three binding names *share* this single object {x: 10}. And
absolutely the same strategy in this case when passing that values to
function arguments.
The example I mentioned above (I wrote it before in private email
discussion with one programmer): <URL: http://gist.github.com/364525>
Dmitry.