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

Discussion in 'Java' started by Lenny Wintfeld, Apr 19, 2006.

  1. 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
     
    Lenny Wintfeld, Apr 19, 2006
    #1
    1. Advertising

  2. 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.
     
    Andrew McDonagh, Apr 19, 2006
    #2
    1. Advertising

  3. Lenny Wintfeld

    Stefan Ram Guest

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

    Andrew McDonagh <> writes:
    >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.
     
    Stefan Ram, Apr 19, 2006
    #3
  4. Lenny Wintfeld

    Adam Warner Guest

    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
     
    Adam Warner, Apr 19, 2006
    #4
  5. 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 <>,
    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.
     
    Lenny Wintfeld, Apr 19, 2006
    #5
  6. "Lenny Wintfeld" <> wrote in message
    news:...
    > 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.

    --
    LTP

    :)
     
    Luc The Perverse, Apr 19, 2006
    #6
  7. On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
    <> 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
     
    Domagoj Klepac, Apr 19, 2006
    #7
  8. 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
     
    Dimitri Maziuk, Apr 19, 2006
    #8
  9. Lenny Wintfeld

    Stefan Ram Guest

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

    Dimitri Maziuk <dima@127.0.0.1> writes:
    >Yes, but Java's fscked-up terminology takes large portion of the


    What does this have to do with fsck?

    http://en.wikipedia.org/wiki/Fsck
     
    Stefan Ram, Apr 19, 2006
    #9
  10. Lenny Wintfeld

    Stefan Ram Guest

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

    -berlin.de (Stefan Ram) writes:
    >Dimitri Maziuk <dima@127.0.0.1> writes:
    >>Yes, but Java's fscked-up terminology takes large portion of the

    >What does this have to do with fsck?
    >http://en.wikipedia.org/wiki/Fsck


    Since by now I actually have read the explanation on this page,
    no answer is necessary anymore.
     
    Stefan Ram, Apr 19, 2006
    #10
  11. Lenny Wintfeld

    Adam Warner Guest

    On Wed, 19 Apr 2006 21:46:26 +0200, Domagoj Klepac wrote:

    > On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
    > <> 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
     
    Adam Warner, Apr 20, 2006
    #11
  12. Lenny Wintfeld

    Oliver Wong Guest

    "Domagoj Klepac" <> wrote in message
    news:...
    > On Wed, 19 Apr 2006 14:23:45 +1200, Adam Warner
    > <> 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
     
    Oliver Wong, Apr 20, 2006
    #12
  13. Lenny Wintfeld

    Guest

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

    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.
     
    , Apr 20, 2006
    #13
  14. Re: C++ programmer stumbles over pass by value. Need advice.

    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
    --
    All whitespace is equivalent except in certain situations
    -- ANSI C standard committee
     
    Dimitri Maziuk, Apr 20, 2006
    #14
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.

Share This Page