C++ programmer stumbles over pass by value. Need advice.

L

Lenny Wintfeld

Here's a model of my problem. I see what's causing it (thinking in C++,
with pass by reference) but I don't see a Java way to solve it. Probably
because I'm so new to Java.

Here's the problem.

2 methods inside the same class. Method1 passes a String array to
method2, relying on method2 to process the string array and return a
String and a new String array for further processing back to method1.

public boolean method1 (String s1, other args)
{
//do some stuff
String [] sa1 = null; // to be created and returned by method2
String s2 = null; // to be created and returned by method2

Method2(s1, sa1, s2)l

//do some important stuff with sa1 and s2

return true;
}


// C++ type method (unfortunately)
private void method2 (String s1, String [] sa1, String s2)
{
//do some stuff
StringTokenizer st = new StringTokenizer(s1, "/");

String sRemainder;

sRemainder = st.nextToken();
s2 = st.nextToken(); // just a string to be returned

sa1 = sRemainder.split(","); // a string array to be returned
}


The eclipse debugger confirms that method 2 is processing the strings
exactly as I want it to. sa1 and s2 after the processing look great
inside method 2. But they're null after the return to method1. I assume
this is because sa1 and s2 are copies inside method 2 and they go out of
scope on the return. sa2 and s1 are created inside method2 but I need
them for further work in method 1.

I obviously coded this like a C/C++ programmer. What I'd like to know is
what's the conventional methodology (or programming idiom) for passing
back lots of stuff created in one method to it's caller? Feel free to
hack up the above example to show me how, if it's convenient.

Thanks in advance for your help/

Lenny Wintfeld
 
A

Andrew McDonagh

Lenny said:
Here's a model of my problem. I see what's causing it (thinking in C++,
with pass by reference) but I don't see a Java way to solve it. Probably
because I'm so new to Java.

Here's the problem.

2 methods inside the same class. Method1 passes a String array to
method2, relying on method2 to process the string array and return a
String and a new String array for further processing back to method1.




The eclipse debugger confirms that method 2 is processing the strings
exactly as I want it to. sa1 and s2 after the processing look great
inside method 2. But they're null after the return to method1. I assume
this is because sa1 and s2 are copies inside method 2 and they go out of
scope on the return. sa2 and s1 are created inside method2 but I need
them for further work in method 1.

I obviously coded this like a C/C++ programmer. What I'd like to know is
what's the conventional methodology (or programming idiom) for passing
back lots of stuff created in one method to it's caller? Feel free to
hack up the above example to show me how, if it's convenient.

Thanks in advance for your help/

Lenny Wintfeld

For starters, try to stop thinking in C++ - easier said than done
admittedly, but worth it.

In Java, References are passed by value. The objects they point to
aren't actually moved or copied at all.

Primitives (ints, boolean, long, etc) are always passed by value.

So this leaves only two ways of returning things from methods.

1) the method's returned type. In your example, you could change the
method signature to return something rather than its current 'void'.

2) Pass in a reference to a Data holder object, inside the method set
the value within the Dataholder to what ever it is you want to return.

Either way works for sending by single or multiple values. For multiple
values it just means you'll have to wrap then in something.

Data holder passed in parameter list example:

class StuffReturnedByMethod2 (
String [] sa1 = null; // to be created and returned by method2
String s2 = null; // to be created and returned by method2
}

public boolean method1 (String s1, other args)
{
//do some stuff
StuffReturnedByMethod2 returnedStuff = new StuffReturnedByMethod2();
Method2(s1, returnedStuff )

//do some important stuff with sa1 and s2

String[] sa1 = returnedStuff.sa1;
String s2 = returnedStuff.s2;

return true;
}


// C++ type method (unfortunately)
private void method2 (String s1, StuffReturnedByMethod2 stuffToReturn)
{
//do some stuff
StringTokenizer st = new StringTokenizer(s1, "/");

String sRemainder = st.nextToken();
stuffToReturn.s2 = st.nextToken(); // just a string to be returned

stuffToReturn.sa1 = sRemainder.split(",");
// a string array to be returned
}


This might look - hacky or cheap, but what we tend to find, is that we
have more smaller classes in Java, which are highly focused upon one
job. These classes might startout being mere data holders, but usually,
very quickly they start attracting behaviour or state too.
 
S

Stefan Ram

Andrew McDonagh said:
In Java, References are passed by value. The objects they point to
aren't actually moved or copied at all.

This is like in C++, for the case that

- one thinks of Java references as corresponding to C++ pointers
(quotation from the JLS3, 4.3.1:
»The reference values (often just references) are pointers«

- one thinks of a subset of C++ without »reference parameters«

- one thinks of a subset of C++, that does not allow
all objects as arguments, but only pointers and some
primitiv objects.

Therefor, the situation in Java is a special case of
the situation in C++.
So this leaves only two ways of returning things from methods.
1) the method's returned type.
2) Pass in a reference to a Data holder object,

One also might pass in a »continuation«.

For example, someone might want to return a pair.
This (»getPair«) is not valid Java:

class Server
{ static java.util.Random rand = new java.util.Random();
static( int, int )getPair( final Client client )
{ return( rand.nextInt( 11 ), rand.nextInt( 21 )); }}

class Example
{ public void main()
{ java.lang.System.out.println( Server.getPair( this )); }}

Instead, one might pass in the »continuation«:

interface Client { void continuation( int x, int y ); }

class Server
{ static java.util.Random rand = new java.util.Random();
static void getPair( final Client client )
{ client.continuation( rand.nextInt( 11 ), rand.nextInt( 21 )); }}

class Example implements Client
{ public void continuation( final int x, final int y )
{ java.lang.System.out.println( x + ", " + y ); }
public void main()
{ Server.getPair( this ); }}

public class Main
{ public static void main( final java.lang.String[] args )
{ new Example().main(); }}

Here, the server does not »return« the int-pair to the calling
method, but to the calling object (to the method
»continuation«), insofar the word »return« could still be
used.
 
A

Adam Warner

Here's a model of my problem. I see what's causing it (thinking in C++,
with pass by reference) but I don't see a Java way to solve it. Probably
because I'm so new to Java.

Here's the problem.

2 methods inside the same class. Method1 passes a String array to
method2, relying on method2 to process the string array and return a
String and a new String array for further processing back to method1.

What you're actually after is multiple return values ("return a String and
a new String array" => two return values). Unfortunately Java provides no
efficient construct for multiple return values. They were removed before
the first release of Java. I'd like to locate the 1997 interview
referenced in this Usenet post:
<http://groups.google.com/group/comp.object/msg/580bc83193356221?dmode=source>

Gosling may just be being folksy, but I find the following
answers from a language designer as really poor:

G:> Yeah. I actually had an implementation of Mesa-style
G:> multiple value returns mostly implemented just before
G:> 1.0 that I ripped out because I was uncomfortable with
G:> the semantics, and the schedule was getting tight.
G:> Right now, I really regret it.

The next thing you may try to do with a language that doesn't implement
multiple return values is pass the values upon the stack via a pointer.
This will be less efficient than multiple return values passed in
registers but more efficient than heap-allocated multiple return values.
This approach is also impossible in Java.

This leaves building an object to pass the values in. You have the choice
of whether the caller should pass an object for the callee to mutate or
whether the callee builds a fresh object to hold the multiple return
values.

You may be inclined to pass a container object to the callee to mutate
since the container can be reused by the caller. I suggest the callee
should build a new container for multiple values each time because the
most sophisticated JVMs will soon be able to avoid heap allocation (and
perhaps even stack allocation) via escape analysis. Thus we are close to
the point where Gosling's omission of explicit multiple return values will
no longer be a hindrance to efficiently returning multiple values. While
your code is likely to run slower in the meantime it's the future-proof
option.

Regards,
Adam
 
L

Lenny Wintfeld

Thanks very much for your comments and advice. It's been a long day
(about 12 straight hours coding) so I'll try using your suggested "reply
class" or "return class" tomorrow. Though I can't imagine having
trouble with that method.

If there's any trouble (which I doubt) I'll post it back on this thread.

Thanks again

Lenny Wintfeld
 
L

Luc The Perverse

Lenny Wintfeld said:
Thanks very much for your comments and advice. It's been a long day
(about 12 straight hours coding) so I'll try using your suggested "reply
class" or "return class" tomorrow. Though I can't imagine having
trouble with that method.

If there's any trouble (which I doubt) I'll post it back on this thread.

Thanks again

Lenny Wintfeld

Remember to keep a positive attitude. Remember, this is not an annoying
workaround to fix a problem with the language - but rather simply the way
the language is meant to be used ;)

I imagine that you will find, as I did, that you will find this generally
helps you to make cleaner more readable code.
 
D

Domagoj Klepac

This leaves building an object to pass the values in. You have the choice
of whether the caller should pass an object for the callee to mutate or
whether the callee builds a fresh object to hold the multiple return
values.

You may be inclined to pass a container object to the callee to mutate
since the container can be reused by the caller. I suggest the callee
should build a new container for multiple values each time because the
most sophisticated JVMs will soon be able to avoid heap allocation (and
perhaps even stack allocation) via escape analysis. Thus we are close to
the point where Gosling's omission of explicit multiple return values will
no longer be a hindrance to efficiently returning multiple values. While
your code is likely to run slower in the meantime it's the future-proof
option.

Wait a second.

Are you saying that in a future JVMs objects won't be "passed by
reference", and that a program like this:

public class PassByReference {
public static void appendFive(StringBuffer s1, StringBuffer s2) {
s1.append(" two");
s2.append(" three");
}

public static void main(String[] args) {
StringBuffer str = new StringBuffer("one");
PassByReference.appendFive(str, str);
System.out.println(str);
}
}

....won't print "one two three" but "one"?


Of course, using Strings or primitives in this example would print
"one", and this is a bit "dirty", and is not something I'd recommend
as a best practice, and ESPECIALLY to a C++ programmer :)))... but it
is a useful hack in a few rare cases, where it can save you from
creating a class just to return several objects.

Domchi
 
D

Dimitri Maziuk

Lenny Wintfeld sez:
Here's a model of my problem. I see what's causing it (thinking in C++,
with pass by reference) but I don't see a Java way to solve it. Probably
because I'm so new to Java.

Yes, but Java's fscked-up terminology takes large portion of the
blame. In Java "reference values" are pointers passed by value.
Assignment operator simply re-points the pointer (not like C++
references), whereas dereferencing operator does what you
expect: e.g. you can modify the object by calling its mutator
methods (not like "pass by value").
Here's the problem.

2 methods inside the same class. Method1 passes a String array to
method2, relying on method2 to process the string array and return a
String and a new String array for further processing back to method1.

public boolean method1 (String s1, other args)
{
//do some stuff
String [] sa1 = null; // to be created and returned by method2
String s2 = null; // to be created and returned by method2

Simple for sa1:
String [] sa1 = new String[N];
(provided N is known beforehand, otherwise use ArrayList). For s2
the trick is that strings are "immutable" (have no mutator methods),
so you need to use a mutable version: StringBuilder (1.5+ only) or
StringBuffer:
StringBuilder s2 = new StringBuilder();

Creating a separate class for return value only makes sense where
you'd return a struct in C++. In this case I'd probably not bother
anyway : you can as easily return s2 as 1st element of your array.

Dima
 
A

Adam Warner

This leaves building an object to pass the values in. You have the
choice of whether the caller should pass an object for the callee to
mutate or whether the callee builds a fresh object to hold the multiple
return values.

You may be inclined to pass a container object to the callee to mutate
since the container can be reused by the caller. I suggest the callee
should build a new container for multiple values each time because the
most sophisticated JVMs will soon be able to avoid heap allocation (and
perhaps even stack allocation) via escape analysis. Thus we are close to
the point where Gosling's omission of explicit multiple return values
will no longer be a hindrance to efficiently returning multiple values.
While your code is likely to run slower in the meantime it's the
future-proof option.

Wait a second.

Are you saying that in a future JVMs objects won't be "passed by
reference", and that a program like this: [...]
...won't print "one two three" but "one"?

Optimisations via escape analysis must not change existing program
semantics. What it will mean is that objects treated like primitives
(where object identity is irrelevant) will likely be as fast as if the JVM
had explicit support for those primitives.

A great example is an immutable complex number class. To return an
immutable complex number one returns a new complex object. In the vast
majority of cases the object's existence is fleeting. All the calling code
does is extract the real and imaginary fields before losing its object
reference. Current the Sun JVM always builds the complex object and this
increases garbage collection activity and reduces locality of reference.
Soon the Sun JVM will be able to deduce that it doesn't need to create the
object. Behind the scenes it will get those fields to the caller via a
different route. This route may be the stack or machine registers.

From another perspective this complex number is the return of TWO values.
These optimisations will also apply to the return of conceptually
discrete multiple values that are wrapped up in a single return object.

Whenever you hold onto a return object past the caller's lifetime it will
continue to be heap allocated to preserve program semantics.
... but it is a useful hack in a few rare cases, where it can save you
from creating a class just to return several objects.

Without an additional syntactic blessing from Sun you'll have to
explicitly wrap up and extract multiple return values.

These optimisations aren't just necessary for a few rare cases. They are
critical for high performance object-oriented operation upon
primitive-style objects.

The remaining critical omission from the JVM is a new set of arrays with
64-bit (long) array indices. This will not affect existing code as long
array indices are currently a compile time error. While easy to implement
and critical for some scientific computing tasks I do not see Sun taking
leadership of this issue. My guess is (an offshoot of) the Harmony project
will eventually force Sun to address this.

Regards,
Adam
 
O

Oliver Wong

Domagoj Klepac said:
This leaves building an object to pass the values in. You have the choice
of whether the caller should pass an object for the callee to mutate or
whether the callee builds a fresh object to hold the multiple return
values.

You may be inclined to pass a container object to the callee to mutate
since the container can be reused by the caller. I suggest the callee
should build a new container for multiple values each time because the
most sophisticated JVMs will soon be able to avoid heap allocation (and
perhaps even stack allocation) via escape analysis. Thus we are close to
the point where Gosling's omission of explicit multiple return values will
no longer be a hindrance to efficiently returning multiple values. While
your code is likely to run slower in the meantime it's the future-proof
option.

Wait a second.

Are you saying that in a future JVMs objects won't be "passed by
reference", and that a program like this:

public class PassByReference {
public static void appendFive(StringBuffer s1, StringBuffer s2) {
s1.append(" two");
s2.append(" three");
}

public static void main(String[] args) {
StringBuffer str = new StringBuffer("one");
PassByReference.appendFive(str, str);
System.out.println(str);
}
}

...won't print "one two three" but "one"?

Obviously, Sun "owns" Java, and they are free do whatever they want with
future versions of the language.

But I think what Adam is saying is that the language and JVM
specifications specify behaviour, not implementation. As long as the above
program prints "one two three", it doesn't matter HOW it does it. It might
do so by passing stuff around by value, or passing stuff around by
reference, or by not passing anything around at all and doing some inlining
magic instead, or maybe something else I haven't come up with yet.

- Oliver
 
S

Scott.R.Lemke

Why not just pass is back as the return value? You are using your
return value's right now for error handling(I am assuming that's what
the true/false return would be used for). Java and C++ have this
wonderful thing called Exceptions. If you look at your false return
situations and think "Hey, this would only return false in a few
exceptional cases", then you have an exception. If you have a situation
where you think "Hey, this is going to return false a lot under normal
circumstances", then you need to refactor.
 
D

Dimitri Maziuk

(e-mail address removed) sez:
Why not just pass is back as the return value? You are using your
return value's right now for error handling(I am assuming that's what
the true/false return would be used for). Java and C++ have this
wonderful thing called Exceptions.

Which, as the name implies, are used to signal "exceptional" circumstances.
There's nothing in OP to indicate that false return from his method is
out of the ordinary and warrants a jump to clean-up/recovery block.

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,744
Messages
2,569,482
Members
44,901
Latest member
Noble71S45

Latest Threads

Top