C to Java migration - how to cope with passing by value only?

  • Thread starter Dobieslaw Wroblewski
  • Start date
D

Dobieslaw Wroblewski

Hi,

Yesterday I tried to write something like (it's not the exact code):

void Foo(Color cl, JButton bn) {
cl = new Color(200, 200, 200);
bn = new JButton("Button");
bn.setbackground(cl);
}

And to my amazement - it did not work as I expected. Then I read in the
tutorial that the references to classes are passed by value in Java...
because everything is passed by value in fact ;-).

I was previously programming mainly in C++ and used passing arguments by
reference or by pointer quite often. Are there any well established
strategies of how to change the way of thinking (this is probably easier ;-)
and how to port the C++ code so that it uses passing by value only? I can
think of passing Object[] to functions like Foo, but this does not seem very
elegant...

DW.
 
K

klynn47

No, references are not passed by value. Only primitive data types are
passed by value.

The problem in your method is that the reference that you are passing
to the method is being discarded, and the formal parameters bn and
color are being pointed at new objects and you can't change anything
about the actual object whose reference was sent to the method.
 
N

Noah Fiedel

Hi DW,
You'll definitely need to change your thinking. I've been
programming Java since the 0.9x releases, and it's a big change from
C/C++. I used .NET for 6 months full-time and although it was
convenient to be able to have in/out/both parameters it was also messy.
I don't miss that language feature at all.
Garbage collection does a lot more than simply remove unused stuff
- if you take advantage of it. Here is how you could implement the same
method successfully.

public JButton createButton(int red, int green, int blue) {
JButton bn = new Jbutton("Button"); //create a new button
bn.setbackground(new Color(red, green, blue)); //set with a new Color
object
return bn; //at this point bn has a reference to the Color object, so
it will not be GC'd
}

This is just an example, but if you used that method, the calling
code wouldn't have to worry about the color at all. It's not great
code, but the idea is that as long as an object is referred to it will
not be GC'd. This is incredibly useful IMHO.
 
D

Dobieslaw Wroblewski

No, references are not passed by value. Only primitive data types are
passed by value.

Objects are passed by reference, however the references themselves are
passed by value. It means that the function gets copy of the passed
reference (although it refers to the same object). So you can manipulate the
original object's members but you cannot assign a new object to it.

DW.
 
D

Dobieslaw Wroblewski

You'll definitely need to change your thinking.

:)

Garbage collection does a lot more than simply remove unused stuff
- if you take advantage of it.

I did not think garbage collection had something to do with passing by value
or reference. In C# you can pass by reference and the garbage collection is
there. Well... maybe it is just easier to implement garbage collection in a
language that does not allow passing by reference... that's all.

Here is how you could implement the same
method successfully. [...]

Well, maybe it was not a best example (in fact I found a workaround quickly)
but let us think of the classical example used e.g. in bubble sort:

void swap(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}

What elegant java translation would you propose in this case?

DW.
 
W

Woebegone

Dobieslaw Wroblewski said:
Hi,

Yesterday I tried to write something like (it's not the exact code):

void Foo(Color cl, JButton bn) {
cl = new Color(200, 200, 200);
bn = new JButton("Button");
bn.setbackground(cl);
}

And to my amazement - it did not work as I expected. Then I read in the
tutorial that the references to classes are passed by value in Java...
because everything is passed by value in fact ;-).

I was previously programming mainly in C++ and used passing arguments by
reference or by pointer quite often. Are there any well established
strategies of how to change the way of thinking (this is probably easier
;-)
and how to port the C++ code so that it uses passing by value only? I can
think of passing Object[] to functions like Foo, but this does not seem
very
elegant...

DW.

Think of the Java method

void foo(A a) {
a = new A();
}

as working like the C method

void foo(A* a) {
a = new A;
}

Neither change the argument itself: just the copy of it they receive through
the parameter, which is not the Object either -- what we're interested in.
In C you have to write

void foo(A** a) {
*a = new A();
}

In C++, with reference parameters, I suspect you're not really doing quite
what you think you're doing either: bear in mind that it's impossible to
reseat a reference, and that a reference can never be null (even though it
can refer to a null "object"), so you can modify the thing a reference
points to but not the reference itself.

If I have the C++

void (A& a) {
a = new A;
}

it's more like the second example than the first.

In your example, you're trying to adjust what the reference refers to rather
than the thing that it refers to, and that can't be done. Like you
considered, you can synthesize another layer of indirection by wrapping your
references in another object, and using that as the parameter:

// Data hiding omitted for brevity...
public class ColorButton {
public JButton button;
public Color color;
}

void foo(ColorButton cb) {
// this is going to throw a null pointer exception if
// cb is null
cb.color = new Color(200, 200, 200);
cb.button = new JButton("Button");
cb.button.setBackground(cb.color);
}

Alternatively, why not omit the arguments and make the button your return
value? You can query it for it's colour (I mean Color) later if you need to
know:

public JButton foo() {
JButton button = new JButton("Button");
button.setBackground(new Color(200, 200, 200));
}

As for the other question, how to get used to it, I think the only way is to
get burned a few times (or many times for some us...) and get used to
consciously avoiding side-effects in functions ( I mean methods).
 
W

Woebegone

8<
Well, maybe it was not a best example (in fact I found a workaround
quickly)
but let us think of the classical example used e.g. in bubble sort:

void swap(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}

What elegant java translation would you propose in this case?

DW.

I don't think there is an elegant (from C++ pov) translation to this one
since as you've observed Java has no equivalent to a reference to a
primitive, but

void swap(int[] A, int i, int j) {
int temp = A;
A = A[j];
A[j] = temp;
}

gets the job done (granted in context only) and further allows for bounds
checking. One of things I found hardest to adjust to is the absence of any
familiar concept of "address" in Java. Some of these problems really do
require adopting a different mindset, but that's largely by design also.

Oh yeah, and whatever I said earlier about side-effects, well...
 
D

Dobieslaw Wroblewski

void foo(A a) {
a = new A();
}

as working like the C method

void foo(A* a) {
a = new A;
}

Yes, that seems a good analogy.

In C you have to write

void foo(A** a) {
*a = new A();
}

Of course.

In C++, with reference parameters, I suspect you're not really doing quite
what you think you're doing either: bear in mind that it's impossible to
reseat a reference, and that a reference can never be null (even though it
can refer to a null "object"), so you can modify the thing a reference
points to but not the reference itself.

If I have the C++

void (A& a) {
a = new A;
}

The above code does not compile, it should be:

void f(A& a) {
A aa;
a = aa;
}

(and after returning from f the passed object _does_ change)

So, my point of view should be clearer now... if I think a java reference is
similar to C++ reference.
But in this case the similarity with C++ pointers seems to explain more.

So... OK, I can see one can live without passing by reference. One just has
to use class wrappers or arrays/collections whenever the function is to
return many values at once. In fact this is more or less what I expected,
but I wanted to ask in order to avoid reinventing the wheel ;-).

Thanks.

DW.
 
C

Chris Uppal

Dobieslaw said:
I was previously programming mainly in C++ and used passing arguments by
reference or by pointer quite often. Are there any well established
strategies of how to change the way of thinking (this is probably easier
;-)

Just /forget/ about C++. Java is a different language, and works in a
completely different way. Learn it from scratch, rather than by composing C++
in your head and translating (or rather, failing to translate) into Java.

and how to port the C++ code so that it uses passing by value only? I

Don't try to port C++ that is written in that style (rather poor style too,
IMO, though I suppose that's not very relevant). Re-create it (if you must),
but "porting" it will be a nightmare.

-- chris
 
P

Patricia Shanahan

Chris said:
Dobieslaw Wroblewski wrote:




Just /forget/ about C++. Java is a different language, and works in a
completely different way. Learn it from scratch, rather than by composing C++
in your head and translating (or rather, failing to translate) into Java.

This is a very, very, important point. Every language has
its own idioms. Programs written in language B by someone
who is thinking in the idioms of language B can use only the
intersection of the idioms of A and B, often a very limited
language.

They can be as hard to read as prose written in a natural
language by someone who does not know it very well but has a
good dictionary. The individual words may make sense, but
they are not used quite the way they should be, and idioms
are translated literally.

When I'm learning another programming language I find it
easier to work only with books and reference materials for
that language, and skip any "conversion" books that describe
it in terms of another language. The more I ignore the
languages I already know and concentrate on taking the new
language on its own terms the faster I learn.

Patricia
 
E

Eric Sosman

No, references are not passed by value. Only primitive data types are
passed by value.

On the contrary, references *are* passed by value, both
to and from methods/constructors, just like everything else.
 
E

Eric Sosman

Dobieslaw said:
Well, maybe it was not a best example (in fact I found a workaround quickly)
but let us think of the classical example used e.g. in bubble sort:

void swap(int *x, int *y) {
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}

What elegant java translation would you propose in this case?

Since Java doesn't have "naked" pointers, you can't
use this sort of technique to swap two entities that are
"just anywhere." Fortunately, you usually don't have to.
You usually don't want to, either: in your example, the
intent is to exchange two elements of the same array, and
it would be a Nasty Bug if somehow one or both of the
pointers pointed outside that array.

So, there's an array lurking in the background, providing
the storage for the values you want to swap. Well, let's
bring it into the foreground and use array indices instead
of unrestricted pointers:

void swap(int[] array, int i, int j) {
int tmp = array;
array = array[j];
array[j] = tmp;
}

"Elegant?" I don't know; eye of the beholder and all
that. "Clear?" Yes, I think so. (Aside: Anyone who mentions
the XOR hack will be vilified mercilessly.)
 
D

Dobieslaw Wroblewski

Well, I generally agree, but I was just so used to the concept of passing by
reference or pointer (well, it was present in all languages that I had
contact with, e.g.: Pascal, C/C++/C#, Clarion, even VB) that I was quite
puzzled that it might be not present in a serious language like Java ;-).

Anyway, I think that situations when in a single call you want to modify a
bunch of data that is not put together in a class wrapper are natural and
depend on the logic of what you want to do, not on the language...

DW.
 
M

Matt Humphrey

Dobieslaw Wroblewski said:
Well, I generally agree, but I was just so used to the concept of passing by
reference or pointer (well, it was present in all languages that I had
contact with, e.g.: Pascal, C/C++/C#, Clarion, even VB) that I was quite
puzzled that it might be not present in a serious language like Java ;-).

Anyway, I think that situations when in a single call you want to modify a
bunch of data that is not put together in a class wrapper are natural and
depend on the logic of what you want to do, not on the language...

Coming from Smalltalk, I had no problem with Java's
passing-references-by-value. I agree with Patricia--the notion that a
method can modify its parameters is an idiom of C and pass-by-reference
languages and not Java. The notion of input-only parameters is key element
of functional languages and I find that it eliminates the unnecessary
complexity of a method call having potential side-effects of changing the
parameters. In many years of systems development I found not having output
parameters to be better than having them--I don't even use them in C#.

Cheers,
Matt Humphrey (e-mail address removed) http://www.iviz.com/
 
E

Eric Sosman

Dobieslaw said:
Well, I generally agree, but I was just so used to the concept of passing by
reference or pointer (well, it was present in all languages that I had
contact with, e.g.: Pascal, C/C++/C#, Clarion, even VB) that I was quite
puzzled that it might be not present in a serious language like Java ;-).

<off-topic>

Serious language or not, C also lacks pass by reference.

Anyway, I think that situations when in a single call you want to modify a
bunch of data that is not put together in a class wrapper are natural and
depend on the logic of what you want to do, not on the language...

You do such modifications through reference values.
In Java, all non-null reference values must refer to Objects
of some kind, so there's no way to build a reference to non-
Objects like methods, primitives, or other references. In C
it is possible to form pointers to such things, but Java
restricts the set of things that are referencable.

Some people feel this is a flaw in Java -- but they don't
usually suggest that Java would be better if references to
non-Objects were possible. Rather, they hold that there should
be no such thing as a primitive, that everything should be an
Object. Personally, I'm insufficiently indoctrinated to comment
on such arguments one way or the other. Still, your wish to
have primitives be referencable seems quite strange to me -- and
you're certainly the first person from whom I've heard such a
wish. O Pioneer!
 
D

Dobieslaw Wroblewski

Serious language or not, C also lacks pass by reference.

:)))))

I expected this, that's why I wrote about passing by pointer ;-P

Still, your wish to
have primitives be referencable seems quite strange to me -- and
you're certainly the first person from whom I've heard such a
wish. O Pioneer!

:))).

Well, the talk gets more and more philosophical :). As you recall my first
post, I asked about strategies of how to live without something that I was
used to - and how to be elegant. And some answers were of a kind "you have
to forget about your previous life - this life is better, whatever you might
think of it" :)))))).

Yes... I cannot see the point in distinction between primitive types and
objects, and I can see some inconsistency in the fact that you can modify an
object passed to the function, but you cannot replace the object
completely... but... well... I see this as a part of the game... I like Java
anyway :).

DW.
 
D

david.rifkind

DW,
Can you explain why you don't see the distinction between primitive
types and objects? The reason I ask is because in my learning and
understanding of OO principles there is a fundamental difference
between using an object and a primitive. Java is OO, not procedural,
so the concept is that objects send messages to each other. These
messages can be in the form of another object, itself or a primitive
and then does something with what it recieves. Java is not supposed to
be C++ and I think as you say above "You have to forget about your
previous life - this life is better." Is an opinion you should heed
well. Again I tell you, Java is not C++. If you want to code like you
were in C++ than use C++ because it's a different tool, not because you
want Java to be like C++.
Just my opinion.
brill2
 
D

Dobieslaw Wroblewski

This definitely gets philosophical ;-)
Can you explain why you don't see the distinction between primitive
types and objects?

You did not understand me. Of course I can see it... I am just not convinced
why use both...

Java is OO, not procedural,

Exactly... so why use primitives at all? Let everything be an object...

But of course... in a way... such questions are pointless from practical
point of view, so I think that this discussion is not leading to anything
useful and it's a high time to stop it ;-).

"You have to forget about your
previous life - this life is better." Is an opinion you should heed
well. Again I tell you, Java is not C++.

Of course :). And I really like both of the above, so maybe I should
develop a new way of living but I will definitely not forget my previous
life ;-))).

DW.
 
O

opalpa

void Foo(Color cl, JButton bn) {
cl = new Color(200, 200, 200);
bn = new JButton("Button");
bn.setbackground(cl);
}

I've seen similar situations. Explicit distintcion between instances
and references throughout programs is my way of thinking. Instances
exist in the program's constructed state. References are local
accessors to instances. When Foo is executing, before creation of
Color instance, cl refers to a Color instance or null which was
specified by caller. cl is a locally existing reference. cl is
assigned to a newly cretaed Color instance in the constructor. There
is after that no method-local way of accessing the instance which was
originally provided to this constructor. There is a new instance and
it is refered to locally by cl. Notice we have not even mentioed the
reference the caller was using to refer to the instance he passed in.
We also did not change the instance the callers reference refered to.

void (A& a) {
a = new A;
}

The above code does not compile, it should be:

void f(A& a) {
A aa;
a = aa;

}

My C++ is rusty (cause of wonderful .... you know it's coming ...
Java). I believe the second snippet creates an A on the stack and
assigning aa to a does not prevent destructor of aa destorying the
instance which is therefor useless when refered to after function
finish.

The first snipped assigns a pointer (that's what new returns in C++,
right?) to a reference which does not work (right?).
There are a few other ways to write that wrong...
 
D

Dimitri Maziuk

Dobieslaw Wroblewski sez:
....
Yes... I cannot see the point in distinction between primitive types and
objects, and I can see some inconsistency in the fact that you can modify an
object passed to the function, but you cannot replace the object
completely... but... well... I see this as a part of the game... I like Java
anyway :).

All objects are subclasses of Object (this is necessary, for one thing,
to make garbage collection work). Primitives aren't.

To some extent you could hide the differences with operator overloading,
but the real kicker is memory allocation.

All objects are allocated on the heap ("new" is a dead giveaway).
Primitives are allocated on the stack. Object references are allocated
on the stack, too (somewhere deep down they're just ints, of course).

So you don't have to garbage-collect your primitives & references, and
you can have the usual scope and visibility rules of a stack-based
compiler. OTOH, you don't need to worry about overflowing the stack
frame by creating a bunch of huge data structures on it: every data
structure is an object, every object is on the heap. You don't have to
worry about the heap too much, either: there's no way to allocate a
non-object there and all Objects inherit the magic that allows them to
be garbage-collected.

Add the rule that everything's passed by value -- makes sense since
all parameters are primitives or pointers sitting on the stack -- and
it's clear why a function can modify but not replace an object parameter:

Reference to object is passed by value into your function. Because it's
by-value, the function cannot replace it with another reference returned
by new. Because it's a reference the function can modify the object.

Dima
 

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,767
Messages
2,569,571
Members
45,045
Latest member
DRCM

Latest Threads

Top