C++ programmer stumbles over pass by value. Need advice.  
Author Message
Lenny Wintfeld





PostPosted: 2006-4-19 8:29:00 Top

java-programmer, C++ programmer stumbles over pass by value. Need advice. 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

 
Andrew McDonagh





PostPosted: 2006-4-19 8:55:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. Lenny Wintfeld wrote:
> 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.
 
Adam Warner





PostPosted: 2006-4-19 10:24:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. On Tue, 18 Apr 2006 20:29:02 -0400, Lenny Wintfeld wrote:
> 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
 
 
Lenny Wintfeld





PostPosted: 2006-4-19 11:41:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. 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



In article <email***@***.com>,
email***@***.com says...
> 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.
 
 
Luc The Perverse





PostPosted: 2006-4-19 12:09:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. "Lenny Wintfeld" <email***@***.com> wrote in message
news:email***@***.com...
> 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.

:)


 
 
Domagoj Klepac





PostPosted: 2006-4-20 3:46:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
<email***@***.com> wrote:
>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
 
 
Dimitri Maziuk





PostPosted: 2006-4-20 4:40:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. 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
--
The speed at which a mistyped command executes is directly proportional
to the amount of damage done. -- Joe Zeff
 
 
Adam Warner





PostPosted: 2006-4-20 8:15:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice. On Wed, 19 Apr 2006 21:46:26 +0200, Domagoj Klepac wrote:

> On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
> <email***@***.com> wrote:
>>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
 
 
Oliver Wong





PostPosted: 2006-4-20 22:50:00 Top

java-programmer >> C++ programmer stumbles over pass by value. Need advice.
"Domagoj Klepac" <email***@***.com> wrote in message
news:email***@***.com...
> On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
> <email***@***.com> wrote:
>>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