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:31:24 GMT
On Fri, Mar 4, 2011 at 2:29 PM, Matt Benson <gudnabrsam@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.

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<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