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 18:35:38 GMT
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


Mime
View raw message