views:

162

answers:

6

Given a set of tuple classes in an OOP language: Pair, Triple and Quad, should Triple subclass Pair, and Quad subclass Triple?

The issue, as I see it, is whether a Triple should be substitutable as a Pair, and likewise Quad for Triple or Pair. Whether Triple is also a Pair and Quad is also a Triple and a Pair.

In one context, such a relationship might be valuable for extensibility - today this thing returns a Pair of things, tomorrow I need it to return a Triple without breaking existing callers, who are only using the first two of the three.

On the other hand, should they each be distinct types? I can see benefit in stronger type checking - where you can't pass a Triple to a method that expects a Pair.

I am leaning towards using inheritance, but would really appreciate input from others?

PS: In case it matters, the classes will (of course) be generic.

PPS: On a way more subjective side, should the names be Tuple2, Tuple3 and Tuple4?


Edit: I am thinking of these more as loosely coupled groups; not specifically for things like x/y x/y/z coordinates, though they may be used for such. It would be things like needing a general solution for multiple return values from a method, but in a form with very simple semantics.

That said, I am interested in all the ways others have actually used tuples.

A: 

I'd go with 0,1,2 or infinity. e.g. null, 1 object, your Pair class, or then a collection of some sort.

Your Pair could even implement a Collection interface.

If there's a specific relationship between Three or Four items, it should probably be named.

[Perhaps I'm missing the problem, but I just can't think of a case where I want to specifically link 3 things in a generic way]

Stephen
I like the idea of being a collection; probably List. Not map, because Pair is not meant to be the equivalent of Map.Entry.
Software Monkey
+1  A: 

It seems to me that you should make a generic Tuple interface (or use something like the Collection mentioned above), and have your pair and 3-tuple classes implement that interface. That way, you can take advantage of polymorphism but also allow a pair to use a simpler implementation than an arbitrary-sized tuple. You'd probably want to make your Tuple interface include .x and .y accessors as shorthand for the first two elements, and larger tuples can implement their own shorthands as appropriate for items with higher indices.

+1  A: 

it depends on the semantics that you need -

  • a pair of opposites is not semantically compatible with a 3-tuple of similar objects
  • a pair of coordinates in polar space is not semantically compatible with a 3-tuple of coordinates in Euclidean space

if your semantics are simple compositions, then a generic class Tuple<N> would make more sense

Steven A. Lowe
+1  A: 

Different length of tuple is a different type. (Well, in many type systems anyways.) In a strongly typed language, I wouldn't think that they should be a collection.

This is a good thing as it ensures more safety. Places where you return tuples usually have somewhat coupled information along with it, the implicit knowledge of what each component is. It's worse if you pass in more values in a tuple than expected -- what's that supposed to mean? It doesn't fit inheritance.

Another potential issue is if you decide to use overloading. If tuples inherit from each other, then overload resolution will fail where it should not. But this is probably a better argument against overloading.

Of course, none of this matters if you have a specific use case and find that certain behaviours will help you.

Edit: If you want general information, try perusing a bit of Haskell or ML family (OCaml/F#) to see how they're used and then form your own decisions.

MichaelGG
Can you enhance your answer with a (quick/simple) example of where overloading fails?
Software Monkey
BTW, it was playing with Haskell that I was first exposed to the concept of tuples. :)
Software Monkey
+1  A: 

Like most design related questions, the answer is - It depends.

If you are looking for conventional Tuple design, Tuple2, Tuple3 etc is the way to go. The problem with inheritance is that, first of all Triplet is not a type of Pair. How would you implement the equals method for it? Is a Triplet equal to a Pair with first two items the same? If you have a collection of Pairs, can you add triplet to it or vice versa? If in your domain this is fine, you can go with inheritance.

Any case, it pays to have an interface/abstract class (maybe Tuple) which all these implement.

@amit.dev: What methods would the Tuple interface declare?
Software Monkey
@amit.dev: I would think that a Triple is not "equals()" a Pair, because Pair.getClass() != Triple.getClass() - allowing somePair.equals(someTriple) would violate the equals contract because someTriple.equals(somePair) must surely be false.
Software Monkey
@amit.dev: But because somePair is not equal to someTriple, does not mean that someTriple is not an instanceof Pair.
Software Monkey
A: 

Gilad Bracha blogged about tuples, which I found interesting reading.

One point he made (whether correctly or not I can't yet judge) was:

Literal tuples are best defined as read only. One reason for this is that readonly tuples are more polymorphic. Long tuples are subtypes of short ones:

{S. T. U. V } <= {S. T. U} <= {S. T} <= {S}

[and] read only tuples are covariant:

T1 <= T2, S1 <= S2 ==> {S1. T1} <= {S2. T2}

That would seem to suggest my inclination to using inheritance may be correct, and would contradict amit.dev when he says that a Triple is not a Pair.

Software Monkey
Yea immutability is nice. But I don't see any reason for the subtyping so Triple inherits from pair.
MichaelGG