On Fri, Mar 4, 2011 at 1:45 PM, Gary Gregory <garydgreg...@gmail.com> wrote: > On Fri, Mar 4, 2011 at 2:36 PM, Adrian Crum < > adrian.c...@sandglass-software.com> wrote: > >> +1 on the Association interface. >> >> The Tuple interface looks like a Collection, even more so when it expands >> to more than two elements. >> > > Not quite, because you can only type a collection as Collection<E>, not > Collection<E1, E2>. >
>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. 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