Re: programming concepts > specific languages



In article <Pine.LNX.4.60-041.0511101749070.5375@xxxxxxxxxxxxxxxxxxxxx>,
Arthur J. O'Dwyer <ajo@xxxxxxxxxxxxxxxxxxxxx> wrote:
>
> (It might help to read the last part of this first.)
>
>On Thu, 10 Nov 2005, Oliver Wong wrote:
>>
>> "Arthur J. O'Dwyer" <ajo@xxxxxxxxxxxxxxxxxxxxx> wrote...
>>> On Thu, 10 Nov 2005, Oliver Wong wrote:
>>>> "Gerry Quinn" <gerryq@xxxxxxxxxxxxxxxxxxx> wrote...
>>>>>
>>>>> The claim "Java always passes by value" is trivially true but
>>>>> meaningless. Every ordinary language passes parameters on a stack that
>>>>> contains things that can be called values.
>>>>>
>>>>> When you pass a reference, you are "passing by reference", if the term
>>>>> is to have any meaning at all.
>[...]
>> I'm not very familiar with C++, so I can't comment on the the above,
>> except to say that it seems to me that Gerry Quinn posted up C++ code that
>> does something (I'm calling it "pass by reference"), which you cannot do in
>> Java. Here's my understanding of the semantics of C++. Maybe it's wrong:
>>
>> <C++ code?>
>> void function1() {
>> int i = 5;
>> function2(&i);
>> cout << i;
>> }
>>
>> void function2(int &i) {
>> &i = 10;
>
> The above line has invalid syntax --- it should be 'i = 10;'. This does
>indeed modify the value of 'i' back in 'function1', as well as in
>'function2' --- because both names refer to the same object.
>
>> }
>> </C++ code?>
>
>[... the Java "equivalent"]
>> void function2(MyObject i) {
>> i = new Object(10);
>> }
>> </Java code>
>>
>> Here, the output will again be "5" and not "10".
>
> Right. This is because Java's object model treats assignment differently
>from other operations. If you did the logical thing and modified the
>"value" of 'i' like this:
>
> i.myValue = 10; /* pretend 'myValue' is public in this example */
>
>then you'd see the change back in 'function1', because 'i' /is/ passed
>by reference --- the function call 'function2(i)' passes a reference to
>the object named 'i', rather than its value.
>
> But Java's object model is unintuitive: the assignment 'i.myValue=10'
>changes the original object, but the assignment 'i=new Object(10)'
>actually changes the target of the reference passed to 'function2'.
>C++ disallows changing references in this way --- quite sensibly, I
>think!

I claim that how Java treats non-primitive variables is only
"unintuitive" if (1) you are a C programmer, or (2) you learned
Java from a source that was not precise about terminology.

In C++, if I have a class MyObject and write

MyObject i;

then i is *an instance of the class MyObject*, is it not?
while if I write the same line in Java, i is *a reference that
can point to an instance of MyObject*. No instances of MyObject
are created unless/until one writes something such as

i = new MyObject();

(ignoring for now the ways in which you can create objects with
"reflection", e.g., newInstance() in class Class).

In C++, you could (I believe -- my C++ is more than a little rusty)
get the same effect by writing

MyObject * i;

So, when in Java one writes

i.myValue = 10;

the nearest C++ equivalent is not

i.myValue = 10; (where i is a myObject)

but

i->myValue 10; (where is a pointer to a myObject)

Similarly, when in Java one writes

MyObject i;
MyObject j = new MyObject();
i = j;

the effect is to create one MyObject object, with two references
to it. If you wrote this is C++, exactly what would happen would
depend on whether MyObject had overloaded the "=" operator and how.
Now *that* is a potential source of confusion, IMO, though it does
provide some flexibility Java lacks. To get the same effect as
the above lines in Java, in C++, you would write

MyObject *i;
MyObject *j = new MyObject();
i = j;

(Or so I think -- rusty C++, as I said.)

Anyway. So if you are a C++ programmer, I can understand why
the way things work in Java might seem odd and unintuitive.

People who come to Java without a background in C++ to possibly
lead them astray .... I think some confusion may result from
the fact that people are apt to say that the variable i above
"is a MyObject", when it would be more correct to say that i
"is a reference to a MyObject".

The distinction is, IMO, critical. Once you start viewing Java in
terms of "all variables of non-primitive types are *references to
objects* (not objects themselves)", then everything starts to seem
consistent and reasonable. Well, that was my experience anyway.
I guess YMMV.

>
>> In fact, short of using reflection, there is nothing function2
>> can do to change the fact that function1 is going to print out 5.
>
> Yes, I believe we all agree on that point. It's just that I claim
>that that fact is counterintuitive and indicative of bad language design,
>while you claim it's consistent and (presumably) indicative of good
>language design.
>

Another vote here for "consistent, once you understand how things
work".

As for "counterintuitive" -- I would claim that what "intuitive"
means depends on a lot on one's background. GUIs are said to be
very intuitive, but I still remember how baffling I found Windows
at first, after many years working in mostly-CLI environments.
Eventually I sorted out enough of the basic ideas to get past some
of my initial misconceptions, but it took some, um, interesting
learning experiences.

>
>>> I (mostly) agree with Gerry: Java's pointer model is inconsistent,
>>> because some things (ints, doubles) behave one way, and some things
>>> (objects) behave another. And apparently some things (Strings) behave
>>> a third way; I hadn't known that before.
>>
>> Strings DO behave differently from other types of objects which behave
>> differently from primitives. It would be quite a useless class library if
>> every object in it behaved in exactly the same way! But the way in which
>> they are passed between method calls follows the exact same rule: everything
>> (whether it be a primitive or a reference to an object) is passed by value.
>
> I must have misunderstood what Gerry said earlier, then.
>

It's possible, too, that Gerry was confused. I think he's wrong
about under-the-hood copying when one passes immutable objects,
for example.

>
>
>>> Certainly it's not sensible to say Java "passes by value," except
>>> for ints, doubles, and other primitive types. Objects in Java are passed
>>> by reference, but with unintuitive semantics with respect to assignment.
>>
>> You lost me here. I thought primitive types in particular behave in the
>> way that C++ programmers would readily call "pass by value".
>
> Yes. Java passes primitive types by value, and objects by reference.
>That is, 'f(i)' passes a new copy of the value of 'i' if 'i' is a
>primitive, but it passes a reference to 'i' itself if 'i' is an object.
>

Well -- no. Java has no ability to pass objects at all. What it
does have is the ability to pass *references to objects*. So f(i)
passes a new copy of i -- whether i is a primitive type or a reference
type. "What if i is neither one? What if it's an object?" AFAIK,
not possible in Java. This may be the critical point.

>
>> I'm starting to realize we have a terminology problem here. There are 4
>> ways I can see Objects being passed from one method to another:
>>
>> 1) The objects themselves are passed by value.
>> 2) The objects themselves are passed by reference.
>> 3) The reference to the objects are passed by value.
>> 4) The reference to the objects are passed by reference.
>>
>> Add to this, 2 ways in which primitive types can be passed from one
>> method to another:
>>
>> 5) The value of the primitive is passed (I call this "pass by value".)
>> 6) A reference to the primitive is passed (I call this "pass by
>> reference".)
>>
>> I think we are in agreement with the terminology for passing primitives.
>>
>> I believe that 2 and 3 are essentially indistinguishable in their end
>> result. I claim that Java does 3 and 5, both of which I call "passing by
>> value". You claim that Java does 2 and 5, thus sometimes passing by
>> reference, sometimes passing by value.
>
> Okay, using this terminology, I agree that Java does 3 and 5, but since
>3 involves silently passing a reference, I call it "pass-by-reference."
>Therefore Java sometimes passes by reference, and sometimes by value.

Only if you think a variable in Java can be an object. But it can't.

>
> The "weirdness" of Java's handling of assignment comes from the fact
>that it does 3 and not 2. C++ does 2, so that
>
> foo.value = 42;
>and
> foo = 42;
>
>behave the same way (both modify the original 'foo' in some way). Java
>does 3, so that the two lines produce radically different effects.
>I call this a bad thing.
>

Only if you think C++ and Java should behave the same way.

C++ allows variables to *be* objects, and to *point to* objects.
Java only allows variables to *point to* objects, and it calls
such variables "references" rather than "pointers", perhaps so
people understand that they aren't exactly like C/C++ pointers.
But in some respects they're similar, since in both cases there's
a distinction between the pointer (reference) and the object it
points to.

Maybe it would have been clearer if Java referenced fields and
methods with the "->" operator rather than the "." operator, since
then I think things might be less confusing for C++ programmers.
Maybe if the designers of Java had foreseen this confusion ....?
Or maybe not. <shrug>

--
| B. L. Massingill
| ObDisclaimer: I don't speak for my employers; they return the favor.
.