Can we talk about the class name and use cases? For me a pair evokes similarity: a pair of shoes, a pair of hands, a pair of coordinates. You get the idea. Having a Pair.of(name, dog) reads like nonsense to me. A Map.Entry.of(name, dog) I understand, same for an Association.of(name, dog) (I cannot escape from my Smalltalk heritage.)
In most cases, I deal with key-value "pairs", let's play: new Pair(name, dog) new KeyValue(name, dog) new Association(name, dog) new MapEntry(name, dog) If we want to accommodate "real" pairs like a Point2D(x,y), which we should, then the Pair name makes perfect sense IF it is a Pair<T> where the x and y are both Ts. There are two uses cases: pairs and key-value associations. It would then be interesting for the Pair<T> and KeyValue(K,V) interfaces to share a common implementing base class, a something that holds two objects (a TwoTuple, yikes?) Let's play (these are immutable for brevity): public interface TwoTuple<E1,E2> { E1 getFirst(); E2 getSecond(); } public interface Pair<T> extends TwoTuple<T, T> { } public interface Association<K, V> extends TwoTuple<K, V> { K getKey(); V getValue(); } Thoughts? Gary On Fri, Mar 4, 2011 at 1:35 PM, Matt Benson <gudnabr...@gmail.com> wrote: > On Fri, Mar 4, 2011 at 5:41 AM, Stephen Colebourne <scolebou...@joda.org> > wrote: > > I now have authoristion from OpenGamma to discuss adding a Pair class > > to [lang] based on our internal classes. If necessary a CCLA can be > > signed, although since we are not necessarily importing the OpenGamma > > classes as is and I'd be writing code in [lang3] with my Apache hat > > on, the CCLA might not be needed. I can also code it in work time :-) > > > > The main goal would be either an abstract class or an interface for > > Pair. We chose an abstract class so that it could have factory > > methods: > > > > Pair<String, Number> p = Pair.of("Foo", 6); > > > > It also allowed more control over the immutability of Pair (although > > because its abstract and holds references to any object, immutability > > cannot be guaranteed). > > > > We then have other concrete classes: > > - ObjectsPair - two generified objects > > - DoublePair - two double > > - IntDoublePair - int and double > > - LongDoublePair - long and double > > - IntObjectPair - int and generified object > > - LongObjectPair - long and generified object > > > > Clearly there are many more possible combinations, but some make less > > sense than others. (Booleans don't waste space, as they are a > > singleton reference, short/float are rarely used) > > > > Beyond this, there are some standard comparators. > > > > Design wise, we implement Map.Entry (makes sense). The primitive > > classes implement primitive map entry interfaces from another library, > > but that wouldn't make sense here. They are comparable and > > serializable (again, one reason for an abstract class). > > > > We name our elements "first" and "second". > > > > The elements are available by methods (for generics) or as public > > final variables from the concrete classes (not the abstract one). The > > methods are getFirst(), getSecond() plus getKey() and getValue() for > > Map compatibility. > > > > The pairs are implemented as immutable. I saw someone mention the > > possibility of a mutable pair, so perhaps we consider that. > > > > I don't want this to be a long process of design or implementation! If > > there isn't rapid consensus, I'd suggest either shipping [lang3] with > > or without the existing class. > > > > Opinions? > > I agree that it would be nice to do whatever we're going to do > quickly, and ship with *something*. On the other hand, I don't want > to ship the existing class without consensus on design, only to give > ourselves (and users) headaches trying to replace it in a subsequent > release. > > I also had the thought that the abstract class would be necessary for > the factory methods. It doesn't seem important, but I'd really like > to be able to say Pair.of(X, Y). Semantically it'd also be nice to be > able to use fields on the immutable variety of Pair (it's perhaps > debatable in light of JIT whether the final field access yields better > performance, so I won't address it--but it *looks* faster :P ), while > still requiring the client to know as little as possible about the RT > type of the Pair. Is it possible to accomplish all these things? > > abstract class Pair<L, R> implements Map.Entry<L, R> { > abstract L getLeft(); > abstract R getRight(); > final L getKey() { return getLeft(); } > final R getValue() { return getRight(); } > static <L, R> ImmutablePair<L, R> of(L, R) {} > } > > class ImmutablePair<L, R> extends Pair<L, R> { > final L left; > final R right; > ImmutablePair(L left, R right) { this.left = left; this.right = right; } > L getLeft() { return left; } > R getRight() { return right; } > static <L, R> ImmutablePair<L, R> of(L, R) {} > } > > class MutablePair<L, R> extends Pair<L, R> { > private L left; > private R right; > > MutablePair(L left, R right) { setLeft(left); setRight(right); } > L getLeft() { return left; } > setLeft(L left) { this.left = left; } > R getRight() { return right; } > setRight(R right) { this.right = right; } > static <L, R> MutablePair<L, R> of(L, R) {} > } > > In the examples above I continue to use the left/right idiom for > reasons of inertia; in the end, I don't *really* care. It seems > examples abound of the various proposed paired names in other > programming contexts, so this becomes a simple matter of taste and/or > majority rules. Personally I prefer left/right as there is less > connotation of priority given either member of the pair as (IMO) in > the case of first/second. > > If we want to extend ImmutablePair for the wrapper types (it wouldn't > seem to make sense to provide access to the primitive equivalent > values in the MutablePair variety), where does it end? If we provide > any such pair types, IMO we should use some predictable rule to > define, for a given wrapper type, what combinations are available, > e.g.: > > * X Double > * X Boolean > * X Object > * X self > * X * ? > > I'm sure I don't have to tell any of my fellow Commons committers that > our components may well have to provide more implementations, or none > at all, compared to equivalent proprietary code, for reasons of > perceived "completeness." If anything this is even more so in the > case of [lang] than perhaps some other Commons components. > > Matt > > > > > Stephen > > > > --------------------------------------------------------------------- > > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > > For additional commands, e-mail: dev-h...@commons.apache.org > > > > > > --------------------------------------------------------------------- > To unsubscribe, e-mail: dev-unsubscr...@commons.apache.org > For additional commands, e-mail: dev-h...@commons.apache.org > > -- Thank you, Gary http://garygregory.wordpress.com/ http://garygregory.com/ http://people.apache.org/~ggregory/ http://twitter.com/GaryGregory