Anonymous tuples (AKA multiple assignment)

0 views
Skip to first unread message

joel.neely

unread,
Feb 17, 2009, 9:32:16 AM2/17/09
to The Java Posse
The discussion of Pair, Triple, Tuple4..Tuple22 etc. makes me wonder
if this isn't too much of a solution. After writing:

Tuple<String,Integer> t = someObject.someMethod();

the caller still may need to do something like:

String s = t._1(); // or "first" or "left" or whatever...
int i = t._2(); // or "second" or "right" etc...

Instead of all that, I'm beginning to think that I'd rather have
simple support for anonymous tuple assignment (or "multiple
assignment"), which could be done in the compiler. (Yes, I know that
Al Perlis said "Syntactical sugar causes cancer of the semi-colon.")
I'm not claiming any great originality here, and will be quite happy
if someone points me to an existing equivalent proposal already in
existence.

This proposal has these parts :

1) LValue lists: Allow a parenthesized, comma-separated list of
variable references or declarations to appear on the left-hand-side of
an assignment. For (partial) example:

(String s, int i) = ...

2) RValue lists: Allow a parenthesized, comma-separated list of
expressions to appear on the right-hand-side of an assignment. For
(remainder of) example:

... = (foo.toString().trim(), foo.childCount());

3) Assignment: Require that the var refs/decls in the lhs list be
assignment-compatible with the values in the rhs list. So, this is
valid:

(String s, int i) = (foo.toString().trim(), foo.childCount());

but this is not:

(int i, String s) = (foo.toString().trim(), foo.childCount());

4) Method declaration: Allow a parenthesized, comma-separated list of
types to appear as the result type of a method definition. For
example:

public (String, Integer) getStuff() {...}

5) Method result: For a method declared as in the previous point,
require all non-exception termination to be in the form of a return
statement with a parenthesized, comma-separated list of expressions
which are compatible with the declared result types (in the sense of
point 3).

public (String, Integer) getStuff() {
if (this.childCollection == null) throw new
IllegalStateException("bletch!"); // lame example
return (this.toString().trim(), childCollection.size());
}

The net effect is that instead of writing something like:

Tuple<String,Integer> t = someObject.someMethod();
String s = t._1(); // or "first" or "left" or whatever...
int i = t._2(); // or "second" or "right" etc...

the programmer would simply write:

(String s, int i) = someObject.getStuff();

and go on about the real work. In addition the multiple-assignment
idiom has been around for a long time, in many languages, allowing
such niceties as:

(a, b) = (b, a);

as a nice way to swap the values of two (mutually-assignment-
compatible) variables.

I'm not opposed to discussion of other punctuation (instead of "(",
")", and ","). I used parens instead of braces above to minimize risk
of confusion with nested scopes, but there may be other alternatives
to consider.

Reinier Zwitserloot

unread,
Feb 17, 2009, 11:12:56 AM2/17/09
to The Java Posse
To summarize Joel Neely's argument:

"I think java should have tuple packing and unpacking exactly as
python has it".

agreed, sort of. We really have to decide if we want java to become a
structural/nominal hybrid language. Right now java is strictly
nominal. BGGA wants to add functional types, which is structural
typing (I don't give you a Comparator, nono, I give you an {Integer,
Integer => int} - that's not nominal typing). Tuples also smack of
structural typing (in a nominally typed world, every tuple would be
granted a name). We can do both - support an 'unpacking' interface, in
the same vein as Iterable, which has the effect that the unpacking
assignment will load each LHS variable with something given by the
appropriate getTupleValues() call that the Unpackable interface
requires you to have.

There's still the issue of generics. Scala solved this by creating 22
tuple classes. I don't think this is an acceptable solution. Pair-wise
generics requires more generics syntax before you can use it, and if
ever you need to make an explicit mention of the generics type, it's a
total horrorshow (Tuple<String, Tuple<Integer, Tuple<List<String>,
Nothing>>> is what you'd actually have to write when all you meant was
a (String, Integer, List<String>) tuple). It seems logical to just add
N-tupled generics parameters, but that's not exactly a simple change
to make.

Python doesn't have this problem because python is not statically
typed - all python's reference types are effectively 'Object' and all
member access is on a runtime lookup basis. (also known as duck
typing).

The easiest solution, but it feels hackish to me, is to auto-generate
the tuple classes.

Tor Norbye

unread,
Feb 17, 2009, 3:42:20 PM2/17/09
to The Java Posse
I definitely agree with this. This is precisely what I tried to argue
for when I say I want multiple return value support. I do NOT want to
simply add Tuple classes to the library. I want to be able to say
"return x, y, z" from a method for example, and similarly be able to
extract the arguments with a straightforward syntax. The tuple stuff
is just plumbing infrastructure for the compilerS I think (yes, plural
- it would be good to have this be -standard- and not javac specific
such that you can call across languages for these methods.)

-- Tor

phil.s...@gmail.com

unread,
Feb 17, 2009, 4:08:48 PM2/17/09
to The Java Posse
Tor, is it possible to post the NetBeans Pair class?

Agreed though, would be great to have return x,y,z. Seems easy enough
too, just implement as an array behind the scenes

Ben Schulz

unread,
Feb 17, 2009, 4:52:23 PM2/17/09
to The Java Posse
I don't think the proposal is bad, but you still have to define what a
tuple is. For instance, I really hope this would still be valid code:

Object o = ("", 1); // Object's famous top type semantics*

Anyways, I really think this should go farther than Java The Language,
but -- similar to Neil Gafter's function types -- tuples should be
part of Java The Platform.

PS: If you have not already, see Neil's excellent talk on Java The
Platform:
http://www.infoq.com/presentations/gafter-jvm-closures
(The URI suggests it's all about closures, but it's not.)

Ben Schulz

unread,
Feb 17, 2009, 4:55:58 PM2/17/09
to The Java Posse
I could kick myself, it's Neal, not Neil -- sorry.

With kind regards
Ben

Viktor Klang

unread,
Feb 17, 2009, 4:56:44 PM2/17/09
to java...@googlegroups.com
For me a tuple is the equivalent of a struct.

What'd be nice in my book is to be able to unify parameter lists and tuples and default parameter values.
But not for JAva, I'll let this come to me in Scala instead :)
--
Viktor Klang
Senior Systems Analyst

Michael Neale

unread,
Feb 17, 2009, 7:33:41 PM2/17/09
to The Java Posse
yes I have recently lost all interest in the java language - it seems
futile to spend effort talking about changes - the amount of effort
required to effect a change is mammoth. So start fresh. It feels
good !

Casper Bang

unread,
Feb 17, 2009, 9:35:58 PM2/17/09
to The Java Posse
Agreed. The topic was taken for a spin on the Fan discussion board
before Christmas where it boiled down to the problem of how to keep
such power confined to internal API's only, where it belongs:
http://www.fandev.org/sidewalk/topic/399

I always wondered if type inference across a (final) method dispatch
couldn't solve the problem in a more OO fashion, but for that to be
possible we'd need automatic properties so there goes that idea.

/Casper

Neal Gafter

unread,
Feb 20, 2009, 2:33:44 PM2/20/09
to The Java Posse, Neal Gafter, Reinier Zwitserloot
On Feb 17, 8:12 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> agreed, sort of. We really have to decide if we want java to become a
> structural/nominal hybrid language. Right now java is strictly
> nominal. BGGA wants to add functional types, which is structural
> typing (I don't give you a Comparator, nono, I give you an {Integer,
> Integer => int} - that's not nominal typing).

Well, not quite. List<String> is the same type as List<String> not
(only) because they have the same name, but because they have the same
type arguments. That's structural typing, and generics are indeed
structurally typed. As are arrays. Java is not strictly nominal.

> Scala solved this by creating 22
> tuple classes. I don't think this is an acceptable solution. Pair-wise
> generics requires more generics syntax before you can use it, and if
> ever you need to make an explicit mention of the generics type, it's a
> total horrorshow (Tuple<String, Tuple<Integer, Tuple<List<String>,
> Nothing>>> is what you'd actually have to write when all you meant was
> a (String, Integer, List<String>) tuple). It seems logical to just add
> N-tupled generics parameters, but that's not exactly a simple change
> to make.

Indeed, the whole point of structural typing is the eliminate the
syntactic mess. One could define (T,U) as meaning identically the
same thing as Pair<T,U>, and then you get the best of both worlds.
BGGA doesn't actually introduce an extension to the type system for
function types - they are defined as shorthand for an instance of a
system-provided nominal interface type. The structural behavior of
BGGA's function types is due to the fact that generic types are
already structurally typed in Java.

> The easiest solution, but it feels hackish to me, is to auto-generate
> the tuple classes.

And somehow make sure that they're the same type when accessed from
different class loaders, etc. Yes, that's the usual technique for
defining structural types.

-jn-

unread,
Feb 22, 2009, 9:29:39 AM2/22/09
to The Java Posse
Not so much.

On Feb 17, 10:12 am, Reinier Zwitserloot <reini...@gmail.com> wrote:
> To summarize Joel Neely's argument:
>
> "I think java should have tuple packing and unpacking exactly as
> python has it".
>

I'd have summarized it more as "multiple assignment doesn't require a
full implementation of Tuples and structural typing, and offers
additional notational conveniences."

I didn't write in terms of tuples and Python (or Perl, Ruby, etc.)
deliberately, to avoid the excess baggage. Although use of anonymous
tuples is one way to implement what I described (and a nice one at
that), it isn't the only way. (Just as "hidden go to statements"
aren't the only way to think about, or implement, iterative program
structures.)

Dijkstra discussed "concurrent assignment" on p. 28 of /A Discipline
of Programming/ (copyright 1976), and the concept was already well
known by then.

James Iry

unread,
Feb 22, 2009, 10:50:39 PM2/22/09
to The Java Posse
If you just want multiple return/assignment there are quite a few ways
to deal with the problem. One common way is to try to just push
multiple values on the stack. But I think the design of the current
JVM pretty much limits you to using TupleN classes, a list structure,
or arrays. Still, there are advantages to TupleN classes. For
example the classes can support methods beyond just unpacking the
fields, instances can be used via non-Java JVM languages without
necessarily changing those languages, etc.

By the way, Scala makes tuples pleasant by sprinkling a tiny bit of
syntactic sugar over TupleN classes so that (a,b,c) syntax works as a
shortcut for Tuple3(a,b,c). But it turns out that multiple assignment
in Scala is just one case of a general construct in the language. You
can write

case class Person(id : Int, name : String, age : Int)

def lookupPerson(id : Int) : Person = // some person lookup code

val Person(_, name, age) = lookupPerson(1)

println("person with id 1 has name " + name + " and age " + age)

This code
1) Declares that we want to be able to unpack and match instances of
Person (that's what "case class" means)
2) Looks up the person
3) Unpacks the resulting person into the name and age variables (the
underscore says skip the id since we already know it).
4) Prints the name and age


In Scala the multiple assignment

val (a,b,c) = (1,2,3)

is just sugar over

val Tuple3(a,b,c) = Tuple3(1,2,3)

And that in turn is just one case of a generalized pattern matching
mechanism that's available to you and your code as shown in the Person
example.

Hamlet D'Arcy

unread,
Feb 25, 2009, 2:19:15 PM2/25/09
to The Java Posse
Is there an accepted standard equals() implementation for Tuple?

I wrote a Pair class (Tuple2) in my codebase over a year ago and it's
been surprising to see how many people have started using it. We had
to broach the equals() method question last week when we started using
them as keys in a map.

Two questions we asked are
1. Are tuples ordered? Tuples seem ordered to me. ("foo", "bar") is
not equal to ("bar", "foo").
2. Are nulls equal? (null, null) seems equal to (null, null) given
that the type of the tuples are the same... but how can you easily
discover the generic type at runtime?

Robert Fischer

unread,
Feb 25, 2009, 2:31:20 PM2/25/09
to java...@googlegroups.com
The generic type is gone, and there's no way to get a handle on it, either at runtime or compile
time. http://enfranchisedmind.com/blog/2007/05/17/the-generics-controversy/

Tuple equality is basically the same as List equality in Java due to type erasure.

~~ Robert.
--
~~ Robert Fischer.
Grails Training http://GroovyMag.com/training
Smokejumper Consulting http://SmokejumperIT.com
Enfranchised Mind Blog http://EnfranchisedMind.com/blog

Check out my book, "Grails Persistence with GORM and GSQL"!
http://www.smokejumperit.com/redirect.html

James Iry

unread,
Feb 25, 2009, 3:25:19 PM2/25/09
to java...@googlegroups.com
Yes, tuples are ordered. ("foo","bar") is not the same as ("bar", "foo").   One way to think of tuples is as records or structures where the name given to each field is it's position in the tuple.  So the first tuple is (1 => "foo", 2 => "bar") while the second is (1 => "bar", 2 => "foo")

To answer your other question look at this:

class Foo...
class Bar extends Foo

Bar x = new Bar
Foo y = x

x.equals(y) ?
y.equals(x) ?

Of course you expect them to be equal since they have the same identity.  But even if I take identity out of the equation we would still expect equality

Bar x = new Bar(1)
Foo y = new Bar(1)

Given a typical definition of equality for Bar we would expect these two to be equal.  So static types don't generally affect equality. Thus a Pair<A,B> might be equal to a Pair<C,D>.  In particular, (null, null) should probably always be equal to (null,null) regardless how the compiler statically typed them.

Hamlet D'Arcy

unread,
Feb 25, 2009, 3:31:12 PM2/25/09
to The Java Posse
Yes, I understand erasure. But a motivated developer could always
concoct some hideous workaround out of type tokens.



On Feb 25, 1:31 pm, Robert Fischer <robert.fisc...@smokejumperit.com>
wrote:
> Enfranchised Mind Bloghttp://EnfranchisedMind.com/blog
Reply all
Reply to author
Forward
0 new messages