On Fri, Mar 4, 2011 at 3:31 PM, Matt Benson <gudnabr...@gmail.com> wrote:
> On Fri, Mar 4, 2011 at 2:29 PM, Matt Benson <gudnabr...@gmail.com> wrote: > [SNIP] > > From http://en.wikipedia.org/wiki/Tuple: "a 2-tuple is called a > > pair". Not necessarily authoritative, but amusing nevertheless. > > > > Another interesting concept mentioned in this article is the > > summarized by the statement "Another way of formalizing tuples is as > > nested ordered pairs." I would argue that this is the only efficient > > way to formally represent an n-tuple using Java generics without > > writing one class per value of n. > > Well, perhaps not "efficient," but still the only way to represent an > arbitrary number of type parameters. > In this case, we need a 2-tuple, nothing more. We can more later of course, a la .NET or not. Gary > > Matt > > > > > Call it a pair, call it an association, but let's call it done. > > > > Matt > > > >> Gary > >> > >> > >>> > >>> -Adrian > >>> > >>> On 3/4/2011 11:24 AM, Gary Gregory wrote: > >>> > >>>> 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 > >>>>> > >>>>> > >>>>> > >>>> > >>> --------------------------------------------------------------------- > >>> 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 > >> > > > > --------------------------------------------------------------------- > 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