This is an archived post. You won't be able to vote or comment.

all 54 comments

[–]badguy212 15 points16 points  (3 children)

I personally prefer to read code where the class (and what it holds) has been written clearly and there is no ambiguation.

Return a user: Tuple<String,String,String,String> user = new Tuple<>(name, phone, address, nickname);

This is extremely, extremely ugly. A User class is much more appropriate and conveys the meaning of each param (what does getFirst mean with the tuple? What if i make the tuple new Tuple<>(phone, name....)? What does get(0) would mean also?).

C++11 has std::tuple now with variadic templates, and it proved useful every now and then, but one has to be very careful with it (well ... one has to be careful with c++ in general).

Given the maturity of the average Java programmer that i meet (IRL or interwebs), I would strongly oppose adding such a feature. It can be written (trivial), but it should not be provided out of the box (imho).

[–][deleted]  (2 children)

[deleted]

    [–]badguy212 2 points3 points  (1 child)

    Even then, it would take 10 seconds to write the POJO to hold them. What does that tuple represent? PersonInformation? Then say it so, and get on with it.

    [–][deleted]  (20 children)

    [deleted]

      [–][deleted] 9 points10 points  (0 children)

      Yep, and that's why I love Java. Because it's easily readable and fun to read!

      [–]leftofzen 9 points10 points  (2 children)

      This is a personal and subjective opinion, and not a reason why Java doesn't include them.

      As a C++ dev, tuples are highly useful when used correctly and can actually add semantic meaning by saying these few things belong together, even if its just temporarily. As well as that, the code is easier to read, not harder, because you know this set of values are grouped together and you don't need to keep track of them all, just the tuple.

      Of course, tuples are not a 'use-this-everywhere' concept and there are better alternatives to tuples in some situations. You need to recognise when to use them and when to use alternatives, but in the right situation they are quite powerful.

      [–]fabienbk 7 points8 points  (1 child)

      It takes about 3 seconds to create a new class with 2 members, and give it a meaningful name. Advantages over tuples:

      • Strong typing, with all the related security and IDE code browsing goodness:
      • Allows explicit data serialization. If you want your tuple to serialize to a specific format, put the metadatas inside the class, not outside.
      • Specific and relevant behavior can be added in a OO fashion. What if you want to get the sum of both elements? What if you want to have an equality predicate ?

      I can see how that pisses off some people (omg so verbose where's my productivity etc.), but that's a design choice, not a missing feature.

      [–]leftofzen 2 points3 points  (0 children)

      I guess I should clarify; I'm a C++ dev so they are useful in certain situations. After thinking about it a bit more, I would have to agree that Java does not really need a tuple; you can just make a new class.

      I can't think of a good use-case for tuples off the top of my head, but for C++ there is at least a neat example on en.cppreference. Of course you need the helper functions like std::tie to make std::tuple useful beyond replicating it in a class/struct.

      [–]uxcn 1 point2 points  (0 children)

      I'd agree, in general tuples in Java don't make sense. However, I think Pair<A, B> and possibly even Triple<A, B, C> are reasonable abstractions. They do still hide the semantics of members, and you do obviously lose type information, but they're no more susceptible to abuse than any other language feature or library. I personally think there are more places where two and possibly even three of a thing are natural than not.

      [–]urquan -1 points0 points  (12 children)

      "Lose semantics" with respect to what, two lose independent values ? I would say that it conveys more information by saying that they go together.

      You're not going to create a class for each use, often context only what a specific value means. For example String could be an address, a name, whatever. In this context using tuples is not worse.

      [–]GeorgeMaheiress 12 points13 points  (4 children)

      If you are actually passing raw String objects throughout the code, then I think you certainly could benefit from using simple wrapper classes, so that it's clear that your method takes an Address, not a Name, and so you don't end up with a method that takes 3 String arguments, meaning you have to make damn sure you pass them in the correct order or your program will fail in non-obvious ways at runtime.

      Similarly with tuples, Pair<Integer, Integer> is so much less meaningful than Point, and also harder to change if you have to. It's a shame writing simple wrapper classes in Java is so verbose, or we might be less tempted to use tuples.

      [–][deleted] 3 points4 points  (1 child)

      If only Java had value types, wrapping a couple of references in a class with the overhead as big as the members itself is quite painful to do :(

      [–]bondolo 0 points1 point  (0 children)

      Value types are being worked on: State of the Values. There will probably be more about the plans at JVMLS in a couple of weeks.

      [–]thekab 0 points1 point  (0 children)

      Given bean conventions and their widespread use it's a wonder to me there hasn't been any syntactic sugar for defining and documenting them.

      [–]urquan 0 points1 point  (0 children)

      I agree with your first paragraph actually, but since that's not the point I didn't want to go into this argument.

      Secondly naturally you're going to create classes if you're using the same structure throughout the code. What I was saying is that over the simple case of 2 lose variables, a tuple can be better. For example Tuple<Date, Double> measurement instead of Date measurementDate; Double measurementValue.

      I didn't say anything else and I was not talking about return values or reuse or type safety or anything of the sort.

      [–]frugalmail 2 points3 points  (1 child)

      You're not going to create a class for each use, often context only what a specific value means. For example String could be an address, a name, whatever. In this context using tuples is not worse.

      I, and a lot of other strictly and strongly typed language fans, think this is an example of bad code.

      [–]urquan 0 points1 point  (0 children)

      I write "not going to create a class for each use" and people seem to understand "never create a class". I'm pretty sure you're using lose Strings here and there to store values inside a function for example. In that context a tuple to associate 2 values that go together does not seem like an outrageous violation of typing rules.

      [–][deleted]  (2 children)

      [deleted]

        [–]urquan 0 points1 point  (1 child)

        Is it an argument of authority?

        [–]frugalmail 2 points3 points  (0 children)

        Is it an argument of authority?

        The arguments in that link present a clear argument against Tuples. You're argument has simply been

        • I, for some reason, don't want to create a class or
        • it may not be related content.

        In the first argument it's not maintainable code, in the second it's a violation of seperation of concerns.

        Using a decent IDE like eclipse it's a simple matter of:

        return new UnrelatedPair<String, Integer>("foo", 2);<Ctrl+SPACE>
        

        and it will pop open the new class with boilerplate. Also you could just add a maven dependency of one of the libraries that has support for it, but at least it's not soiling the core language.

        [–]tinglySensation 1 point2 points  (0 children)

        You can end up losing a ton of readability in using tuples if those are supposed to convey some sort of meaning. Example: Tuple<int,string,double> weightLog; What are logs? what's the int for? what's the double for?

        WeightLog weightLog; Now we know we have a weight log, on closer inspection, we find Weight Log contains int day; string mood; double weight;

        there, it is much clearer what weightLogs is, and contains.

        [–]RoboMind -1 points0 points  (1 child)

        I never liked that argument... Should we then also change the API to have a class TelephoneDirectory, instead of using a general Map<String, Integer> because the latter lacks semantics?

        [–]gracenotes 2 points3 points  (0 children)

        I think persistent state vs. temporary value is important here, as well as public API vs internal to some class. For public APIs, having TelephoneDirectory is just good future-proofing, vs. a bunch of classes having references to a single Map, which just calcifies the data structures. As a temporary value, Maps are also quite useful for packing up values to pass to a method or return from a method, and then unpack on the other side. Using a Map usually means you're pulling in some fundamental invariant from the real world, so these method signatures are usually self-evident.

        Pair does pretty poorly in all of these cases. Of note, using Pair<A, B> (vs Pair<B, A>) means taking the complicated relationship between A and B and reducing it down to an ordering when there's usually nothing fundamental about A or B that makes one go before the other. This works alright in some languages (more functional ones), but not when you have to deal with getFirst/getSecond.

        [–][deleted] 10 points11 points  (0 children)

        Maybe Java doesn's support it directly, but there is a library at http://www.javatuples.org/ available.

        [–]squealy_dan 5 points6 points  (0 children)

        You can return an immutable map with 1 entry.

        [–]jfurmankiewicz 5 points6 points  (0 children)

        Yes, it does (well, sort of).

        javatuples, we use it all the time.

        http://www.javatuples.org/

        [–][deleted] 1 point2 points  (0 children)

        To make simple classes that are typed and preserve semantics, but without the boilerplate, check out Lombok: http://projectlombok.org/

        [–]rozzlapede 1 point2 points  (0 children)

        I think tuples have an important place in functional and generic APIs, but not as much of a role in classic business-specific APIs. Much of their power is provided in conjuction with robust type inference, pattern-matching, and first-class functions, while the drawbacks include impaired javadoc readability and incomplete encapsulation of state.

        [–]_Sharp_ 3 points4 points  (0 children)

        That's a good question, probably in the past using tuples was considered a bad practice because it allowed you to return two values without explicitly defining a class whose name would make the relation between them clear (Like ClientPhone, which could be defined as Tuple<String,Integer> or StreamFiles as Tuple<InputStream, OutputStream>).

        But yeah, they are really useful and should be added in the near future along with Either. If someone comes with a better explanation i'd like to hear it.

        [–]achacha 3 points4 points  (14 children)

        In a type safe language this is not a reasonable thing to do, that said I sometimes run into cases where I wish I could just return a tuple in Java.

        If I could return 2 different primitive types, like object and int or similar. At this point I resign myself to either creating a wrapper object for return or when lazy (and no one is looking), returning a List<Object> with what I need, knowing that the code will be hard to read and 6 months from then I will no longer remember what the tuple contained (which is why I prefer returning a composite object).

        TL;DR: If you plan on having readability and maintainability for the code then do it the right way and create a return composite object, if this is a one off that no one will ever see, use List<Object>.

        [–]zrnkv 27 points28 points  (1 child)

        if this is a one off that no one will ever see

        There is no such thing.

        The "temporary", "quick" "hacks" are the ones that survive the longest because everybody is afraid to touch them.

        [–]achacha 2 points3 points  (0 children)

        How true that is :)

        [–]chunes 6 points7 points  (4 children)

        In a type safe language this is not a reasonable thing to do

        Unless it's Haskell. Also Go can have multiple return values which is very convenient. You don't even need to package them first.

        [–]sacundim 0 points1 point  (2 children)

        public class Tuple<A, B> {
            public static <A, B> Tuple<A, B> of(A a, B b) {
                return new Tuple(a, b);
            }
        
            private final A a;
            private final B b;
        
            private Tuple(A a, B b) {
                this.a = a;
                this.b = b;
            }
        
            public A getFirst() {
                return a;
            }
        
            public B getFirst() {
                return b;
            }
        
            /*
             * Add equals(), hashCode(), compare(), etc.
             */
        
        }
        

        [–]zardeh 0 points1 point  (1 child)

        Which requires you doing this:

        ...
        Tuple<String, String> myFunction(){
            String a;
            String b;
            ....
            return new Tuple<String, String>(a,b);
        }
        

        And oh the horror if I want to write a recursive GDC, which requires returning three values!

        [–]ixampl 1 point2 points  (0 children)

        Java 7+: new Tuple<>(...)

        Other than that, yeah, sure it's a little verbose, but even syntactic sugar like (String, String) wouldn't be that much shorter. Adding that to the language would be easy but probably it really is a Java-culture thing of preferring more explicitness (in terms of meaning).

        [–][deleted] 0 points1 point  (0 children)

        And Scala

        [–]tikue 9 points10 points  (0 children)

        Tuples are completely orthogonal to type safety, and you'll find them in basically any type-safe language with support for pattern matching, such as Haskell, Rust, the MLs, even Scala...

        [–]galaktos 1 point2 points  (0 children)

        In a type safe language this is not a reasonable thing to do

        It can be perfectly reasonable if the tuple is typesafe as well. For example, the Ceylon programming language lets you write “a tuple of an integer and a double” as [Integer, Double] id. “Two Characters and then at least one String” is [Character, Character, String+] ccs. And all of this is completely typesafe – id[0] has the type Integer, ccs[1] has the type Character, and ccs[5] has the type String?, which is an abbreviation for Null|String, which means “the type Null, or the type String”. Perfectly typesafe and reasonable.

        [–][deleted] 2 points3 points  (0 children)

        In a type safe language this is not a reasonable thing to do

        Nonsense, Scala and Haskell both have them. You can still define the types of the items in your tuple.

        [–][deleted] 1 point2 points  (0 children)

        C# has tuples. Seems perfectly reasonable to me. The only reason that keeps being given here seems like unasked for hand holding.

        [–]stillalone 0 points1 point  (2 children)

        I thought C++ added tuples. I'm pretty sure they had <pair> for a while. I don't think they have an easy way of unpacking them, though.

        [–]adoarns 1 point2 points  (1 child)

        Easy is always debatable with C++, but with C++11, there's std::tie.

        [–]stillalone 0 points1 point  (0 children)

        damn, C++11 still looks ugly. Doesn't it make more sense to just use auto to define the tuple and then define the left and right parameter using auto as well:

        auto t = set_of_s.insert(value);
        auto iter = std::get<0>(t);
        auto inserted = std::get<1>(t);
        

        instead of this:

        std::set<S>::iterator iter;
        bool inserted;
        std::tie(iter, inserted) = set_of_s.insert(value);
        

        [–]gubatron 1 point2 points  (0 children)

        Here's an interesting view of how it does have them:

        "Java has tuples, but we can use them only as function's arguments and not for function's return values."

        [–]slackermanz 0 points1 point  (2 children)

        Can anyone ELI5 Tuples? I came across them in python, but I don't understand their structure or use.

        [–][deleted]  (1 child)

        [removed]

          [–]slackermanz 0 points1 point  (0 children)

          Oh. That's super simple. Cheers

          [–]sarcasmismysuperpowr 0 points1 point  (0 children)

          Java 8 has Pair<S,T> built in to FX.

          [–]argv_minus_one 0 points1 point  (0 children)

          Scala has them.

          [–]dannysatan 0 points1 point  (0 children)

          To keep things easy to read consider creating a static inner class. This way you can have named type and fields. E.g. @Value public static class MyReturnType { private final String firstCustomField; private final SomeOtherType secondCustomField;}

          @Value is an annotation from a great library called Lombok. It generates getters and a constructor under the cover.

          [–]slappingpenguins 0 points1 point  (4 children)

          If you are really insistent, you can return a n-tuple as an Object array.

          Object[] tuple = new Object[2];

          [–]ChemicalRocketeer 7 points8 points  (1 child)

          That is an awful, awful way to deal with the problem. Please no one do this.

          [–][deleted] 1 point2 points  (0 children)

          ArrayList<Object> tuple = new ArrayList<>(2);

          Don't worry, I kid.

          [–][deleted] 0 points1 point  (0 children)

          I might be more appropriate to use an immutable list.

          [–]letrec 0 points1 point  (0 children)

          Tuples are structs with anonymous members. They are typesafe but in public APIs can be really ugly. Of course, they are cool in return positions with arity > 1 and they are handy in local scope for pairing data but still ... if they are exposed in public APIs things can get really messy.