commons-dev mailing list archives

Site index · List index
Message view « Date » · « Thread »
Top « Date » · « Thread »
From Matt Benson <gudnabr...@gmail.com>
Subject Re: [lang3] Pair
Date Fri, 04 Mar 2011 20:29:31 GMT
On Fri, Mar 4, 2011 at 1:45 PM, Gary Gregory <garydgregory@gmail.com> wrote:
> On Fri, Mar 4, 2011 at 2:36 PM, Adrian Crum <
> adrian.crum@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<gudnabrsam@gmail.com>  wrote:
>>>
>>>  On Fri, Mar 4, 2011 at 5:41 AM, Stephen Colebourne<scolebourne@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-unsubscribe@commons.apache.org
>>>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>>>
>>>>>
>>>>>  ---------------------------------------------------------------------
>>>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>>>> For additional commands, e-mail: dev-help@commons.apache.org
>>>>
>>>>
>>>>
>>>
>> ---------------------------------------------------------------------
>> To unsubscribe, e-mail: dev-unsubscribe@commons.apache.org
>> For additional commands, e-mail: dev-help@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-unsubscribe@commons.apache.org
For additional commands, e-mail: dev-help@commons.apache.org


Mime
View raw message