Skip to main content

Multiple return values

48 replies [Last post]
lucretius2
Offline
Joined: 2004-12-19
Points: 0

This RFE has now been marked 'Closed, will not be fixed': http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792

The reasons given are (paraphrased by me):
1. It would probably require incompatible changes to the JVM, and the cost of this isn't outweighed by the benefits.

2. The JDK hasn't obviously suffered from the lack multiple return values so far, so would probably make little use of them. This shows it's not an important feature.

3. The logically correct way to return multiple values is to encapsulate them in an object, for instance returning Point is better than returning (int,int). (I think that's what is meant by 'verbose' being better than 'implicit' declarations.)

I find the 3rd point dubious. By this argument, you should only be able to pass a single parameter to a method, since multiple values could be packed into a single object. But of course, multiple values are often not logically related, so you can't define a sensible class to pack the values into. And if you did define such a class, it might only be used once. IMHO the same goes for multiple return values. There's no reason why a method shouldn't produce several results that are unrelated, and so can't be packed into a sensible class.

The example of Point versus (int,int) is specious: of course if a method returns something that's logically a point, a Point object should be returned. But what if (say) a method detecting a mouse click returns a point and a time? You could create a PointTime class, which probably would only be used in this one place; this is not only clunky but it's also just a workaround. The logically correct behaviour is to return two separate entities, a point and a time, and this should be expressible in the code.

Re the 2nd point, that there's no clear need for multiple return values in the JDK: I presume the JDK must have just used workarounds in various places to avoid this limitation. Either by using dubious classes analogous to PointTime, or using several method calls to return several values instead of a single call. Can anyone think of any examples?

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
jarouch
Offline
Joined: 2004-03-04
Points: 0

See, if you were not one of people talking abour this RFE on SUN pages, I would be able to believe - ok, he never saw proposed syntaxes of MRV .. But we all talked about them and THIS is just badly constructed argument stinking with demagogy..

ulfzibis
Offline
Joined: 2005-02-18
Points: 0

@ hlovatt

Good and interesting work, how to implement multiple return values via generics. But why not implementing this functionality by the language ? Noboby is supposed to use it, if he has doubts in respect of error rate. Others can rely on standardised and easier to read syntax.
Other disadvantages:
- You have to add code for triples, quadruples, ...
- T2 requires temporary object creation which implicits loss of performance
- Wrapper objects as Integer require temporary object creation and autoboxing which implicit loss of performance
- access to the single values must be relatively addressed by r.e1 which also means loss of performance
- you are not free to use only one of the return values as in: ( , r1) = foo ( 1, 2);

> ...
> ( r1, r2 ) r = foo( 1, 2 );

Where is r defined ? I think, you mean: ( r1, r2 ) = foo( 1, 2 );

Additionly I propose usage of multiple return values for multi parameter methods as follows:
[code]
(int, int) foo(int x, int y) {
...
return ( x, y);
}
void bar(int x, int y) {
...
}
...
bar( foo( 1, 2));
T2 r = new T2( foo( 1, 2)); // instead of T2< Integer, Integer > r = foo( 1, 2)
[/code]

hlovatt
Offline
Joined: 2003-11-18
Points: 0

I think your concerns can be overcome with a Tuple API:

1. Ability to ignore a returned value, e.g. ( , r2 ) = foo( 1, 2 ) ignores the first value returned. With a Tuple API simply don't refer to r.e1.

2. Efficiency with primitives - Cover the cases of char, int, long, float and double in that order *only*. The bit about "that order *only*" is important since it reduces the number of combinations. Then write Tuples TIC, TII, TIL, TIF, TID, TIO< T >, etc. which are the tuples ( int, char ), ( int, int ), ( int, long ), ( int, float ), ( int, double ), and ( int, Object ) respectively. In the last case, the Object part of TIO is generically typed. Therefore if efficiency for primitives is a concern it can be covered with a tuple API.

I didn't spell out in my original post but there are other distinct advantages in using a tuple API over adding multiple, return values, namely:

1. You can easily convert a tuple class into another class, e.g. class Point extends TII. This is useful for refactoring and is difficult with a multiple return.

2. Often a multiple return is used out of lazyness, so a tuple class is better because it is easy to convert into another class (see above).

3. The tuple classes can have equals and hashCode defined for them, thus they are usable as keys in maps. This isn't possible with multiple returns because they cannot be refered to as a single unit unless yet more syntax is added.

4. The advantages of tuple classes are so great that many languages that have tuples, e.g. Haskel, use a tuple class under the covers.

walter_bruce
Offline
Joined: 2004-11-19
Points: 0

Actually it would be more accurate to say that arrays of int have less space and time overhead because int is not an Object.

The idea that int could become an Object and gain all its abilities (dynamic runtime polymorphism, synchonization locks, etc) without having to pay any overhead is just not feasible with current technology. So you are left with a choice, make the programming APIs simpler/more uniform and always accept the overhead penalty, or add language complexity to allow the programmer to avoid the overhead when it is not needed.

You could image storing all Integer objects in some kind of hashtable to ensure that only one per value, but there will be hashtable overhead on all Integer creation/math and subtle side-effects like sharing of synchronization locks (which apparently is already present).

ulfzibis
Offline
Joined: 2005-02-18
Points: 0

Why not give primitive types the ability to be treated as objects ? Then we wouldn't have to create countless objects to use ints as keys in collections like Map, HashMap etc.

tsinger
Offline
Joined: 2003-06-10
Points: 0

> Why not give primitive types the ability to be
> treated as objects ? Then we wouldn't have to create
> countless objects to use ints as keys in collections
> like Map, HashMap etc.

Although a little bit off-topic, why do you need int-maps or int-list? I only know of one usage, where I need ints in a List: the sorted table to keep the indices of the data rows.

Tom

seane
Offline
Joined: 2005-06-27
Points: 0

just a few comments here and there.

If you need to treat primitive types like and object you can use Intger, Long, etc ...

And about the actual topic of having multiple return values, I must say it not only adds to the complexity of the program, it's really become hard to read, there are other issues, for example: how do you say to the user that howmany return values to expect? howabout casting? wouuld would be the return type of a method? just imagine in a real world where the code could be hundreds of line even thousands, then how you keep the track of what is returned and where. It's also going to impose an overhead of type checking on the Compiler. I would think there are much much much more important issues at this point that need attention, like gui performance, font rendering, etc that are causing java application some problems in the real workd that this little issue which also has a workaround and not many people have complained about, would and should go to the end of the list of enhancement.

You could compare Java with all other widely used languages, like C or C++, which one have multiple return types?

Regards,
Sea

diegof79
Offline
Joined: 2004-01-13
Points: 0

Arghh!! please! no!! noo!!
This adds more complexy to the already overbloated Java syntax.
You are working with a language that uses objects to represent entities from reality. Why you can't represent a multiple value with an object?
instead of: public [x,y] method() {...
use a public MultiValue method() { ..
:P

"- Yes, but is complex to write!"

Then is a problem with the Java syntax, that mades difficult to write collaborations between objects.
But this problem is not solved adding more syntax sugar (for examples what not to do look at Perl!)
Please, read this:
(1) http://www.virtualschool.edu/mon/SoftwareEngineering/BrooksNoSilverBulle...
and this:
(2) http://www.cs.virginia.edu/~evans/cs655/readings/smalltalk.html

Some quotes from (2):
"Good Design: A system should be built with a minimum set of unchangeable parts; those parts should be as general as possible; and all parts of the system should be held in a [b]uniform framework[/b]."
"[b]Uniform Metaphor[/b]: A language should be designed around a powerful metaphor that can be uniformly applied in all areas."

If you add more syntax sugar, the system is less uniform => then more complex (see (1))=> more difficult to read=>more difficult to maintain=>more error prone.

That's why this is not a good idea. Note that in other languajes (see (2)) you can write: 4@3 to represent a Point, but this is still uniform because "@" is a binary message (like "+") sent to the object 2. There is not syntactic differences, and is threat like any other message by the parser and by the VM. (and yes, 4 and 3 are objects and not "ints")

jarouch
Offline
Joined: 2004-03-04
Points: 0

Smalltalk is realy nice example! It has tuples, and if you send message to object, multiple values (parameters) go in, an multiple (returned tuple) out. Nice, symetrical.. Doesn't it look like MRV?:)

diegof79
Offline
Joined: 2004-01-13
Points: 0

No, think that I don't explain my point very well. (maybe because my english is not good, sorry)

Smalltalk doesn't have tuples! only have objects and messages (even the "if" is a message sent to a boolean object).

My point is that adding syntax sugar to the language is not good.
I think that having tuples as a language construct, is bad:

Cons:
- More complex syntax. You have to learn more "exceptions" to the lenguage grammar (for example in the previous post:
don't use <,> for tuples because is alerady used in generic, use (,) -- whitch is confusing for method parameters, then use [,] arghhh!!)
- Incopatible with other versions of the JDK and IDEs
- What is a "multiple return value" in your domain model? It doesn't makes sense, why not a Point, a CoupleJustMarried, a ConfigurationSetting.
If you think that it's the same... let's go and use only Maps to represent objects ;)

Pro:
- You write a little less

Instead of adding tuples I think that is much more important to make Java more uniform:

- No difference between int and Integer, etc. Yes in the 1.5 -or 5- version there is auto-boxing, but this is a ugly patch.

- Make classes behave like real objects, for example you can't do something like this in java:
public method(MyClass.class myClass) {...}
You have to do: public method(Class myClass) {...}
Because there is no "metaclass" MyClass.class, clases are not objects. And "static" methods are not class methods. (you can't override an static method).

alexlamsl
Offline
Joined: 2004-09-02
Points: 0

Why is auto-(un)boxing an ugly patch?

I find it quite an elegant solution to a long-standing problem that most of us wouldn't even dreamt of solving.

lucretius2
Offline
Joined: 2004-12-19
Points: 0

> Why is auto-(un)boxing an ugly patch?
>
> I find it quite an elegant solution to a
> long-standing problem that most of us wouldn't even
> dreamt of solving.

It would be much nicer if an int (or other primitive value) was an Object.

int would be a final immutable class extending Object. '1' would be a unique instance of int. So 1.equals(1) or 1 == 1, no matter what arithmetic operation created the 1. Autoboxing unfortunately is only guaranteed to work like this for numbers between -128 and 127, because these values are cached; other numbers are stored in objects on demand, so that if x == y (for ints x and y) we can't assume (Integer)x == (Integer)y.

Autoboxing also has a space and time overhead, especially for large arrays of values, that would not exist if an int was an Object.

alexlamsl
Offline
Joined: 2004-09-02
Points: 0

I think it is totally sensible to leave the meaning of [b]==[/b] and [b]equals[/b] as they are - for a start, it is for backward-compatibility, and secondly, their meanings of [i]identical[/i] and [i]equal[/i] are vital, seperate concepts in the language.

greeneyed
Offline
Joined: 2003-06-10
Points: 0

@hlovatt: No, Java does not pass-by-reference. But you have to understand what you are "passing".

In your example, you are not passing e1 and e2 as parameters, you are passing the reference to the object minMax and this is the parameter passed by value that you cannot change.

Modifying your example:
[code]
public class Tuple {
...
void static swap( TII inOut ) {
int temp_1 = inOut.e1;
int temp_2 = inOut.e2;
inOut = new TTI(temp_2,temp_1);
}
...
}
...
import static Tuple.*;
...
TII minMax = t( 1, 2 );
swap( minMax ); /* Object minMax is actually NOT changed :) */
[/code]

The object minMax is actually NOT modifyied because inside the method you modify the "reference to it", which was passed by value, so in fact you are modifying a copy.

I hope it clears up what it is meant as "parameters are always passed by value".

-S-

Message was edited by: greeneyed

hlovatt
Offline
Joined: 2003-11-18
Points: 0

@greeneyed

Yes yes - it copies the reference. But since you have a reference the difference is mainly syntactic, in Java you have to manually de-reference it and in other languages the de-reference is automatic. Java is a bit like C were you need a manual de-reference and other languages are like C++ where the de-reference is hidden.

You can modify swap to add a reference to the tuple if you want the ability to make a new tuple and pass the new tuple back. IE pass the tuple by reference by wrapping it in another tuple. (You probably wouldn't do this it is just an example, you would probably use a returned value if you wanted access to newly created objects as opposed to just modifying existing objects - the point of reference passing is to prevent new object creation by reusing old objects!) EG:
[code]
public class Tuples {
...
void static swap( T1< TII > inOut ) {
int temp1 = inOut.e1.e1;
int temp2 = inOut.e1.e2;
inOut.e1 = new TII( temp2, temp1 );
}
...
}
...
import static Tuples.*;
...
TII minMax = t( t( 1, 2 ) );
swap( minMax ); /* Object minMax.e1 has changed :) */
[/code]
Its a bit like C; instead of witting '*minMax', write 'minMax.e1'. The difference compared to C is that you have to use 'minMax.e1' even in the main part of your program and not just in the methods like swap.

It is mainly a syntactic nicety you are talking about - the underlying mechanism is the same - in languages that do references they still pass a copy of the reference. The difference is that in Java you have to use the reference throughout, not just inside the methods.

jwenting
Offline
Joined: 2003-12-02
Points: 0

hlovatt, we understand perfectly well what's going on.
Unlike you it seems we understand that NO references are passed at all.

Unlike C++ where you can pass a reference to an object and replace that reference with another reference causing the original reference (so the one outside the method) to point to another object, in Java you cannot do this.
You can reassign the parameter to another reference inside the method but outside the method this has no effect whatsoever.

If you do the following in Java the results will not be what you would get if you have pass by reference for example
[code]
public class StupidError {
public static void main(String[] args) {
String someString = "Hello World";
doSomethingStupid(someString);
System.out.println(someString);
}

static void doSomethingStupid(String something) {
something = "Hi there";
}
}
[/code]

rogerhernandez
Offline
Joined: 2005-02-23
Points: 0

Well yes, everything is passed by value in Java, including object references. This is different than doing deep copies of objects to pass into a function:

public class MyObject
{
public int value;
}

public class StupidError {
public static void main(String[] args) {
MyObject a = new MyObject ();
a.value = 1;
doSomethingMoreStupid(a);
System.out.println(a.value);
}

static void doSomethingMoreStupid(MyObject obj) {
obj.value = obj.value * 2;
}
}

ramimahdi
Offline
Joined: 2004-05-29
Points: 0

>>First, I am not convinced there are great numbers of people who are strictly against all extensions

thats not true ....... there are fleets in the java community that are againist every new thing

return multiple values from a method is a must and I am sure some time soon it will be added to the .NET ... and it will take the java community few more years to recognize it

I am using MATLAB and its so good

arguing that the multiple values should be included in one object is the most stupid argument because if they have to be related then from OOP the parameters of the method should be related too and hence we should have only argument .......... thats no sense

all the proposed work arounds are not effecient because they are not readable and not supported at the programming time

I am getting sick of not this feature as well as many features

plus none of the old codes will be breaked or having compilation error .......... I dont see what is the point

jwenting
Offline
Joined: 2003-12-02
Points: 0

> >>First, I am not convinced there are great numbers
> of people who are strictly against all extensions
>
> thats not true ....... there are fleets in the java
> community that are againist every new thing
>
No, sensible people are opposed to the rubbish that's being added, not to changes in general.

> return multiple values from a method is a must and I
> am sure some time soon it will be added to the .NET
> ... and it will take the java community few more
> years to recognize it
>
If you don't like Java, get out and don't let the door hit you in the back.

> I am using MATLAB and its so good
>
So use Matlab and complain to them that it's not Java rather than complain here that Java isn't Matlab.
Let's see how they respond (though most likely you'll be laughed out of the building there).

> arguing that the multiple values should be included
> in one object is the most stupid argument because if
> they have to be related then from OOP the parameters
> of the method should be related too and hence we
> should have only argument .......... thats no sense
>

It makes no sense to return multiple unrelated things from a method either, so if you need to do that your design is inherently flawed.

>
> I am getting sick of not this feature as well as many
> features
>
yes, I'm getting sick of all the idiots screaming for "features" which are justified either by their own ignorance or by "XXXXX has it".

ramimahdi
Offline
Joined: 2004-05-29
Points: 0

darline I would recommend you to read the this old bug report

http://bugs.sun.com/bugdatabase/view_bug.do?bug_id=4222792

which sun closed claiming that they have more important things to do than this one and offereing awkward workaround solutions

and see how many reasons are there to include this feature

the paraticipation of the bug forum was really long because the feature is so important to developers and can handel many things quickly

and the other way is only creating meaningless classes just to compine more than one value to get out of a method which kills readability

or to creat different methods to get every value seperately which is more stupid and kills the performance

the readability level of returning more than one value is the same as passing more than one value to the method .......... no big difference dude except in your mind

jwenting
Offline
Joined: 2003-12-02
Points: 0

I hope misguided fanatics like you never get control of the language or it'll go down the drain even faster than is happening already.

laurapiersol
Offline
Joined: 2003-06-13
Points: 0

Multiple return values are a great feature that really could and should be added to Java. All this talk on how its "not object oriented" and "just return a Point class where needed" definitely doesn't match my programming experience.

Multiple values ARE and MUST BE returned by functions that perform multiple calculations in the same formula. No way to change the math so its just a fact. If you accept the FACT that certain formulas calculate multiple results then the only question is how to return the multiple results.

1.) Use value references (or some combination of value references) like:

// void foo(int[] results); // function definition.
int[] resultsArray = new int[2];
foo(resultsArray);
int result1 = resultsArray[0];
int result2 = resultsArray[1];

2.) Return an array of results:
// int[] foo(); // Function definition.
int[] results = foo();
int result1 = results[0];
int result2 = results[1];

Obviously there are other even more obscure ways to cache the multiple results until needed but lets be real here. These 2 ways make code longer, more cryptic, and prone to errors. Forgetting efficiency for a second there is an easy simple solution that requires no change to the JVM, just the compiler.

The following function:

[int a, double b] foo() {
return [1, 2.0];
}

compiles to :

@MultiReturn(int, double)
Object[] foo() {
return new Object[]{new Integer(1), new Double(2.)};
}

or maybe use a synthetic class for return :

synthetic class foo$multiresult {
int result0() { return 1; }
double result1() { return 2.0; }
}

and could be called like:

int a;
double b;
[a, b] = foo();

or maybe even a more terse format:

[int a, double b] = foo();

No change in the JVM is needed just a simple (hopefully) extension to the compiler and the addition of an Attribute if necessary. I'm sure the synthetic Class is also an option (might help enforce syntax). I leave the best compiler solution to the compiler architects.

I don't really care about the syntax just as long as its simple and terse. Adding a new feature to Java doesn't NECESSARILY make the language more complicated or difficult to use as some here keep saying. This proposal will make Java code simpler to read and write.

hlovatt
Offline
Joined: 2003-11-18
Points: 0

A couple of comments on these general discussions:

1. Every one is focusing on primitives; e.g. why doesn't Java allow call be reference, it does (it uses it all the time for objects). You can always get call by reference by wrapping, e.g. in an array, in a custom object, or in a tuple (see TI and TID below).

2. Almost all the examples are trivially handelled with a tuple class, e.g. laurapiersol's example could be:
[code]
import static Tuples.*;
...
TID foo() { return t( 1, 2 ); }
...
TDI aB = foo();
[/code]
Where Tuples is:
[code]
public class Tuples {
public static class TI {
public int e1;
public TI( final int e1 ) { this.e1 = e1; }
}
public static TI t( final int e1 ) { new TI( e1 ); }
...
public static class TID extends TI {
public double e2;
public TID( final int e1, final double e2 ) {
super( e1 );
this.e2 = e2;
}
}
public static TID t( final int e1, final double e2 ) { new TID( e1, e2 ); }
}
[/code]

jwenting
Offline
Joined: 2003-12-02
Points: 0

> A couple of comments on these general discussions:
>
> 1. Every one is focusing on primitives; e.g. why
> doesn't Java allow call be reference, it does (it
> uses it all the time for objects). You can always get
> call by reference by wrapping, e.g. in an array, in a
> custom object, or in a tuple (see TI and TID below).
>
Which shows your complete lack of understanding of parameter passing in Java.
Java is pass by value ALWAYS, what you think is pass by reference is actually references being passed by value (as they should be).

hlovatt
Offline
Joined: 2003-11-18
Points: 0

@jwenting

I do get how Java works :)

The example below demonstrates swapping values using pass by reference and a Tuple API:

[code]
public class Tuple {
...
void static swap( TII inOut ) {
int temp = inOut.e1;
inOut.e1 = inOut.e2;
inOut.e2 = temp;
}
...
}
...
import static Tuple.*;
...
TII minMax = t( 1, 2 );
swap( minMax ); /* Now maxMin :) */
[/code]

sjasja
Offline
Joined: 2004-08-15
Points: 0

Let's see what the creators of Java have to say on whether Java has pass by reference:

"There is exactly one parameter passing mode in Java -pass by value- and that helps keep things simple."
[i]The Java Programming Language, 2nd ed. by Ken Arnold and James Gosling, section 2.6.1, page 40, 3rd paragraph.[/i]

No, Java does not have pass by reference.

hlovatt
Offline
Joined: 2003-11-18
Points: 0

@sjasja

I think you are completely mis-understanding what they mean. They mean a copy of the reference is passed, i.e. the reference itself is passed by value. Not that you don't have reference types. All the objects reside on the heap and a reference to them is stored either in other objects or in the case of local variables (including method arguments) on the stack. Take a look at:

http://java.sun.com/docs/books/jls/third_edition/html/typesValues.html

This is the latest addition of the book you referenced.

It explains clearly the difference between primitives and objects and uses the terms primitive value and reference value. See sections 4.1, 4.2, and 4.3.

If Java doesn't have pass by reference, how does the example of swap I gave above work?

What Java doesn't have and some languages have; is references to primitives, therefore you need to wrap the primitive in an object to get a reference to it. This also introduces a subtle difference compared to some languages, when an object is allocated it is on the heap and only a reference to it can be on the stack. Some languages allow references to primitives and objects that are on the stack or on the heap, e.g. C++.

sjasja
Offline
Joined: 2004-08-15
Points: 0

> I think you are completely mis-understanding
> what they mean.

I understand quite exactly. I very much understand that there is exactly one parameter passing mode in Java: pass by value.

I understand that Java has NO pass by reference.

> They mean a copy of the reference is passed,
> i.e. the reference itself is passed by value.

Yes! There is exactly one parameter passing mode in Java: pass by value. You cannot "demonstrate swapping values using pass by reference" because Java only has one parameter passing mode: pass by value. Java has NO pass by reference.

> If Java doesn't have pass by reference,
> how does the example of swap I gave above work?

A pointer (reference) to the object is passed by value. There is NO pass by reference in Java. Only pass by value.

"Pass by reference" and "passing a reference by value" are
different things. <- This is an important thing to understand. Read it carefully, then re-read, loop until you understand it.

That will help you understand the following sentence: "There is exactly one parameter passing mode in Java -pass by value- and that helps keep things simple."

hlovatt
Offline
Joined: 2003-11-18
Points: 0

In J5 you can use this:
[code]
public class Tuples {
public static class T2< E1, E2 > {
public final E1 e1;
public final E2 e2;
public T2( final E1 e1, final E2 e2 ) {
this.e1 = e1;
this.e2 = e2;
}
}
public static < E1, E2 > T2< E1, E2 > t2( final E1 e1, final E2 e2 ) {
return new T2< E1, E2 >( e1, e2 );
}
// T3 etc.
}
[/code]
Then to define a method and use the method that returned the tuple you would write:
[code]
import static Tuples.*;
....
T2< Integer, Integer > foo( int x, int y ) {
return t2( x, y );
}
....
T2< Integer, Integer > r = foo( 1, 2 );
[/code]
Your syntax gain is none existent, i.e. with multiple return syntax the above example would be:
[code]
( int, int ) foo( int x, int y ) {
return ( x, y );
}
....
int r1;
int r2;
( r1, r2 ) r = foo( 1, 2 );
[/code]
Note: the above example is a worst case example when an object, Integer, is used for a primitive, int, and the version using multiple, return values is longer!!!!!! (6 lines instead of 5)

Why bother with the trouble of the extension that is more verbose?

walter_bruce
Offline
Joined: 2004-11-19
Points: 0

There are some good arguments against multiple return types but these don't seem to be them. Even if multiple return types is not added to Java, let's at least be sure we're doing it for the right reasons.

Extra type checking overhead on the compiler? Type checking overhead is the same as for adding an extra method parameter, ie, insignificant.

How do we keep track of all these return values? The same way you do now with methods that return a single value, by checking the method name, type signature and/or javadoc for the methods that are being called.

It takes 6 lines instead of 5? How about if we declare the ints on a single line as "int r1, r2;". There now it is only 5 lines, does that make it better? Maybe we should count characters instead of lines? :)

The tuple mechanism is a valid programming idiom and could be taken as the official Java solution. What I dislike about it is all the extra casting and temporary object creation. I hope that when Sun next makes a substantial change to the Java language (most recent changes have been relatively simple syntatic sugar), they will consider adding some mechanism for multiple return types.

seane
Offline
Joined: 2005-06-27
Points: 0

Hi Walter bruce,

the type checking is not insignificant for a compiler, it could be "insignificant" for a file of 20 lines, but in a commercial real world software development, where I work and where you deal with files of about 12,000 to 20000 lines each, then it becomes very much significant(don't tell me it's not a good practise having such a long file, I know but it's just the way it is). Plus type checking in most cases comes with casting.

"How do we keep track of all these return values? The same way you do now with methods that return a single value, by checking the method name, type signature and/or javadoc for the methods that are being called."

again I should point to the real world where each method could be about 2000 lines, and that's where it becomes not only really confusing but also extremely error prone. just imagine you need to return many values in different places, you need to throw exceptions, what happens if one value is set and the other throws exception, etc.

" There are some good arguments against multiple return types but these don't seem to be them"

your good reason against this was casting, didn't I mention that in my comments?

adding an overhead of complexity to the user is a significant issue, are you telling me that little example of 5 lines instead of 6 lines represent the real world? if so I think you should get out there and explore a little bit.

walter_bruce
Offline
Joined: 2004-11-19
Points: 0

2000 line methods in 20000 line files? I'm really glad I don't have to maintain that code. I don't see how multiple return values would add any significant type checking cost (at least to the compiler) over and above the type checking that it already has to do. Cost should be equivalent to checking the type of one or two extra method arguments. You cannot have methods that differ solely on return value so it does not add to the method disambiguation costs. Doing the type checking should be very straightforward.

As for Tuples, they can be very powerful and useful. But the implementation using Generics and many different classes for primitive combinations does get to be rather ugly in Java. If Java had native support for Tuples, I think that would be a great way to add multiple return values to Java.

lucretius2
Offline
Joined: 2004-12-19
Points: 0

If tuples were used to implement multiple return values, it would be 'neat' if tuples were defined in such a way that method parameters were also tuples.

i.e. calling a method could be described as simply .

This implies that the tuple syntax was a comma-separated list of values inside parentheses. This would probably prove to be ambiguous, since (1) could be an int unstead of a tuple containing an int; but even if tuples had a different syntax like [1], they could be harmonized with method parameters by making the [ ]s optional in a method call, like this:

( ) where has optional [ ]s.

The rules for type conversion, autoboxing etc. when calling methods would apply to tuples as well:

float x, Object y = [1,2.0]; // convert 1 to float, 2.0 to Double

Method overloading, optional parameters etc. would not have any bearing on tuples; they would just affect the compile-time decision about which method was being called.

The main benefit of this would be to reduce the number of concepts in the language. The way that method parameter types are handled is a bit of an anomaly at the moment, and unifying them with tuples would knock some sense into them.

Anyone know if any other languages treat parameters as tuples in this way?

hlovatt
Offline
Joined: 2003-11-18
Points: 0

You can get the 'tuple acting as an argument list behavior' by overloading the method, e.g.:
[code]
import static Tuple.*;
...
TII foo( int x, int y ) { return t( x, y ); }

TII foo( TII xY ) { return foo( xY.e1, xY.e2 ); }
[/code]
In this case it is useful if the definition of longer tuples builds on smaller ones and the tuples start with the degenerate case of 1 element, i.e.:
[code]
static class T1 ...
static class T2 extends T1 ...
static class T3 extends T2 ...
...
static class TI ...
static class TIC extends TI ...
static class TII extends TI ...
...
[/code]

lucretius2
Offline
Joined: 2004-12-19
Points: 0

> You can get the 'tuple acting as an argument list
> behavior' by overloading the method, e.g.:

My (admittedly quite sketchy) idea was not to make tuples act like argument lists, but to make argument lists actually [b]be[/b] tuples (at the Java language level - obviously not at the JVM level).

It seems to me that this is the kind of orthogonality found in Python/Ruby - which helps account for the elegance and popularity of those languages. Orthogonality seems to be somewhat lacking in Java, and some of the new features in Java 5 seem to reduce it not increase it.

hlovatt
Offline
Joined: 2003-11-18
Points: 0

I think you are going further than asking for multiple return values, what you are asking for is a second typing mechanism to be introduced. I think you would like structural typing, this is where any identical structure is the same type (the names are just for convenience). This is different than Java where the name determines the type. EG in Java Point, Complex, and Interval would be different types even if they all consisted of the same structure ( double, double ).

You can get structural typing by treating the tuple library as your base, e.g. using one of the tuple classes instead of using Object, e.g.:
[code]
class Tuple {
...
static class TDD< T extends TDD< T > > extends TD {
double e2;
/* Factory method that can be overridden with a covariant return type */
T instance( double e1, double e2 ) { return new TDD< TDD >( e1, e2 ); }
...
}
...
}
class Point extends TDD< Point > {
Point( double e1, double e2 ) { super( e1, e2 ); }
Point instance( double e1, double e2 ) { return new Point( e1, e2 ); } /* Overridden factory method */
...
}
class Complex extends TDD< Complex > {
Complex( double e1, double e2 ) { super( e1, e2 ); }
Complex instance( double e1, double e2 ) { return new Complex( e1, e2 ); } /* Overridden factory method */
...
}
class Interval extends TDD < Interval > {
Interval( double e1, double e2 ) { super( e1, e2 ); }
Interval instance( double e1, double e2 ) { return new Interval( e1, e2 ); } /* Overridden factory method */
...
}
[/code]
Now you can write a method:
[code]
/* Calls the factory method so that swap returns a correctly typed object, e.g. if argument in is a Point then a Point is returned */
static < T extends TDD< T > > T swap( T in ) { return in.instance( in.e2, in.e1 ); }
[/code]
Method swap will accept a TDD, a Point, a Complex, or an Interval because they all extend TDD or are TDD. The good with structural typing is that you only wrote one swap method and it can operate on many classes, the bad points are:

1. The fields are public and therefore you can't change what a field does or eliminate a field, e.g. if Complex was implemented with e1 as the real part and e2 as the imaginary part then that is what they would always have to be and you couldn't change your mind and make e1 the magnitude and e2 the phase without breaking old code.

2. The methods that operate on a structure might not have the best name, e.g. swap is not the best name for either Point where transpose is better or Complex where conjugate is the norm. You could of course introduce the other names into classes Point and Complex respectively, so this is a fairly minor objection (so long as people use the better names!).

3. Just because a type has the same structure doesn't mean that all operations are applicable. In an interval type the fields are ordered, i.e. e1 would be the lower limit and e2 the upper, swapping the fields makes no sense and would put the interval into an illegal state. Therefore all the interval methods would have to check that the fields were correctly ordered and throw IllegalStateException if there was a problem, this extra checking is a considerable burden on both the programmer and at runtime.

Therefore you can get the effect that you want, in your own code, without requiring a language change by using a Tuple API. Most people find structural typed programs harder to understand than named typed programs therefore I doubt structural typing will be introduced into Java. Also since you can get the effect that you want, structural typing, without a language change, it really doesn't seem worth the bother of new syntax.

boereck
Offline
Joined: 2005-07-17
Points: 0

Out-parameters are used in several languages to offer multiple return values. I don't know why java doesn't have out- or var/ref-Parameters(call by reference). Perhaps because java was created to be a simple and easy to learn language. But this simplicity leads to larger code that is not necessarily easy to understand. If you know the true reason, please let me know :-)
I don't understand why some poeple are strictly against language-extentions. You don't have to use every feature of a language.

sjasja
Offline
Joined: 2004-08-15
Points: 0

> I don't understand why some poeple are strictly
> against language-extentions. You don't have to
> use every feature of a language.

First, I am not convinced there are great numbers of people who are strictly against all extensions. Each extension needs to be considered from all sides - its good effects as well as bad.

To me, proper OO programming style makes multiple return values unnecessary. A "point" is not returned as a tuple of double,double - it is returned as a Point object. Problem solved. In rare cases the array parameter as return variable trick can be used - after first thinking hard how to implement a real OO solution instead.

Second: "you don't have to use every feature" should not be used as an excuse for adding every feature imaginable. A professional programmer needs to understand the language he uses. He needs to know all the features and the interactions of features. A baroque language with lots of unnecessary overlapping features is hard to learn and hard to understand. And programs become hard to understand, leading to unnecessary bugs.

Also, most programmers don't work in a vacuum. They use libraries written by others. Deciding "I won't use feature X" can be impossible when third party library APIs require the use of that feature. The option "don't use features you don't want" does not exist in the real world.

boereck
Offline
Joined: 2005-07-17
Points: 0

sjasja:
> First, I am not convinced there are great numbers of
> people who are strictly against all extensions.

Hm, maybe I got a wrong picture.

sjasja:
> Each
> extension needs to be considered from all sides - its
> good effects as well as bad.

Of course ervery language change/extention has to be checked carefully. For example I think that backward-compatibility is a very iportant point. I don't want java to be flooded with new features, but I think that moderate changes that ease the development will help java to stay a living language/platform. Of course you can write objects for multiple results, but it causes much more code, which means slower development. And if you introduce many wrapper-objects the code can get confusing and takes longer to understand. I think a concise, comprehensible and typsave syntax for multiple results would be helpful.
Tuples are used in functional languages and I think they work well there. Out-Parameters are used in many languages, and I think they are also working great. Perhaps there are good reasons not to implement one of these, but I don't know a reason except "It can be done with objects right now", which is a weak reason in my opinion.

sjasja:
> Also, most programmers don't work in a vacuum. They
> use libraries written by others. Deciding "I won't
> use feature X" can be impossible when third party
> library APIs require the use of that feature. The
> option "don't use features you don't want" does not
> exist in the real world.

True, I didn't thougt it through when I wrote it. Note to myself: think first, then write :-)

P.S. I had to use a dictionary for some english words. I hope they make sense in this context :-)
And sorry for the massive use of "I think".

subanark
Offline
Joined: 2004-11-26
Points: 0

I don't think you go far enough. What languages need is information rich declerations.
A good syntax for this could be similar to how generics are declared:

[code]
public ,int> someMethod()
{
...
return ;
}

List strings;
int index;
= someMethod();
/*Also works:*/
valuePair = someMethod();
[/code]

I think this makes more sence than c#'s out keyword.

ulfzibis
Offline
Joined: 2005-02-18
Points: 0

You have forgotten:[code]
int index;
<,index> = someMethod();[/code]
Don't use '<>'. [b]Use '()' as they are used for parameters ![/b]
Also let me correct:[code]
public static > (T,int) someMethod() {
...
return (newList,index);
}[/code]
or:[code]
class > C {
public (T,int) someMethod() {
...
return (newList,index);
}
}[/code]
Usage:[code]
(;int index) = someMethod(); // declaration and usage of index
List strings; // declaration of strings
(strings,index) = someMethod(); // usage of strings and index[/code]

jwenting
Offline
Joined: 2003-12-02
Points: 0

Excellent decision to not implement this madness.

lucretius2
Offline
Joined: 2004-12-19
Points: 0

> Excellent decision to not implement this madness.

Well that's a cogent argument .

Something I have never seen is an argument why a method should only return one value, when nobody argues that a method should only take one parameter. Why should there be a difference?

(Now it may be that [i]in practice [/i]methods often only need to return a value. But even if that's true, returning more than one value requires a workaround such as Object[] or an ad hoc class, and languages should not be hobbled by workarounds. There are too many places in Java now where it's considered acceptable that there is 'a way' of doing x, when it's not the logical way.

Warming to my theme: the ascendancy of Python and Ruby is not just because they're scripting languages without much static typing, which Java needn't copy, but because they contain constructs which let you express your program in the most logical and convenient way, not just in a roundabout way. Java should seriously consider adding one or two more fundamental constructs - and I don't mean structs, I mean closures, tuples, well-thought out operator overloading, or whatever.

Now I'm not advocating feature bloat in Java. But the opposite idea, that Java 1.1 was almost perfect and Java 1.5 was pretty much feature freeze for the language, seems to be so prevalent and so unjustifiable that I often put it down to 'groupthink'. Java 1.5 copied some good ideas from C# and added some good ideas of its own, and future versions of Java can and should continue to add gradually the best ideas around. If the main brake on this process is backwards compatibility, then I'm all for a future 'Java+' to be subtly incompatible - maybe marked with a version keyword at the top of a source file. It shouldn't be impossible to allow Java and Java+ classes to interoperate.

OK I'll get off my soapbox now.)

golly
Offline
Joined: 2005-05-11
Points: 0

I agree that this would be useful. The fact that people are working around it should be enough argument (in my opinion).

I think at least, that the javac compiler could just be modified to generate extra code.

Example:

public [String,String] getSomething() {return [a1,b1];}
String a2,b2;
[a2,b2] = getSomething();

could be converted by javac to:

public Object[] getSomething() {
assert a1 instanceof String;
assert b1 instanceof String;
return new Object[]{a1,b1};
}
String a2,b2;
Object[] _tmp = getSomething();
assert a2 instanceof String;
assert b2 instanceof String;
a2 = _tmp[0];
b2 = _tmp[1];

I mean, obviously the people saying that casting as an object array can't complain cos thats exactly what the compiler generates, and the people who wan't multiple return args can't complain either cos they're getting it. I think this solution works for everyone, making coding and type-checking easier and reduces the chance of error. Although of course, instead of asserts, the compiler should generate errors/warnings just as you would expect from this: new HashSet().add("hello");

Actually, probably a more java solution would be this:

public MultipleReturnArgs getSomething() {return ;}
String a2,b2;
= getSomething();

I mean, when u think about it, it's just auto-casting. Same as the following (which is now legal java):

public Int blah() {return 4;}
int asd = blah();

alexlamsl
Offline
Joined: 2004-09-02
Points: 0

That is not auto-casting. Casting an [b]int[/b] to [b]Integer[/b] won't work. It's called Auto-(un)boxing.

blbrown
Offline
Joined: 2005-04-20
Points: 0

I got an email too. I was hoping for this one. Tuples, works really well in Python, I wish they would have checked it out in action.

Most people will just return a generic Object which is a lot harder to debug and causes all kinds of ClassCastExceptions.

Object o = new Object[2];
o[0] = Point;
o[1] = TheTime;
return o;

This code is so verbose, or even creating an object with this kind of encapsulation is even more code.

I guess, a "lambda" style function probably won't pass either.

vhi
Offline
Joined: 2004-10-11
Points: 0

I think you are not being fair. The same code can be written as

return new Object[] {Point, TheTime};

Which is quite compact in my opinion.

Multiple return values mostly indicate a design smell. Either the method is doing many different things (split the method into smaller methods), or it is an indication that a higher level of abstract is required.

jarouch
Offline
Joined: 2004-03-04
Points: 0

Yep, but you have

Object[] bla = call();
point = (Point)bla[0];
time = (TheTime)bla[1];

at the callers side. Do you realy think it is more readable than

(point, time) = call() ??

Next point - you have to use N casts and create useless wrapper.

If you want to return primitive type you have to create an instance of wrapper for it.

Not every function is separable without loss of performance.

How would help you an other level of abstraction in such trivial case as (int, int) moddiv(int, int) operation? It is usually 1 CPU instruction.. Or should we a create wrapper for it?