Peculiar generics problem with static factory method (solved, butinteresting and maybe instructional

Discussion in 'Java' started by John Ersatznom, Jan 7, 2007.

  1. Here's the code snippets.

    @SuppressWarnings("unchecked")
    public static <S extends Scalar<S>, D extends Dimension, T extends
    Point<S, D, T>> Point<S, D, T> getPoint (S component, D dim) {
    if (dim.dimensions == 0) return (Point<S, Zero,
    ZeroDimensionalPoint<S>>)ZeroDimensionalPoint.getInstance(component.getScalarClass(),
    component.isUndefined());


    Compiler claims that it cannot convert Point<S, Zero,
    ZeroDimensionalPoint<S>> to Point<S, D, T>.

    It should warn that the cast requires unchecked conversion instead.

    Changing the cast to (Point<S, D,
    T>)ZeroDimensionalPoint.getInstance(foo) causes "Cannot cast from
    ZeroDimensionalPoint<S> to Point<S, D, T>" instead of a warning.

    Changing it simply to "(Point)" warns of an unnecessary cast. Omitting
    the cast however just gives the first error noted above!

    The @SuppressWarnings("unchecked") annotation doesn't prevent the
    "unnecessary cast" warning.

    Of course, if the method is called with a dim whose "dimensions == 0" it
    is in fact the case that a ZeroDimensionalPoint<S> will be run-time
    compatible with any Point<S, D, T> where S matches up and D is a
    dimension class that defines its dimensions to be zero, with T being
    ZeroDimensionalPoint<S>...

    AFAICT the problem is that D might not actually be Zero, but the base
    class Dimension or a different Dimension subclass that happens to have
    an instance with a dimension of zero. Since the dimension objects are
    just used for run-time dimension-compatibility checking and their
    classes, as type parameters, to allow users of my math classes to have
    compile-time checking for vector math with compile-time-known numbers of
    dimensions, this is annoying. There aren't even ever any run-time uses
    of dimension object instances except to extract "dimensions", call
    toString, and the like.

    Anyone know how to make the compiler ignore the dubious casts?

    Huh -- that's odd. I just solved it myself when I tried

    Point temp = ZeroDimensionalPoint.getInstance(foo);
    return temp;

    I then get "unchecked" warning on "return temp;" which @SuppressWarnings
    makes go away.
     
    John Ersatznom, Jan 7, 2007
    #1
    1. Advertising

  2. Re: Peculiar generics problem with static factory method (solved,but interesting and maybe instructional)

    John Ersatznom wrote:
    >
    > Here's the code snippets.
    >
    > @SuppressWarnings("unchecked")
    > public static <S extends Scalar<S>, D extends Dimension, T extends
    > Point<S, D, T>> Point<S, D, T> getPoint (S component, D dim) {


    I think I'm going to be dumping the use of marker classes to do static
    dimension match checking. Between the proliferation of dubious casts and
    @SuppressWarnings usage, as well as screwy temporaries, it is making the
    code less readable and maintainable (and maybe even correct?) instead of
    more. The last straw was the matrix multiplication method whose
    signature is longer than its body:

    public <U extends Dimension, V extends Dimension, W extends Dimension, X
    extends Matrix<S, E, U, V, X>, Y extends Matrix<S, D, U, W, Y>> Y
    matrixTimes (X that) {

    (in Matrix<S extends Scalar<S>, D extends Dimension, E extends
    Dimension, F extends Dimension, T extends Matrix<S, D, E, F, T> which
    extends Point<S, F, T>)

    C++ lets you use int as a template parameter type, where I could have had

    template <class S, int D, int E> class matrix : point<S, D*E> { ...

    template <int U, int V> matrix<S, D, U> times (matrix<S, E, U> that) {

    OTOH, C++ doesn't have bounding of type parameters, which doesn't let me
    force S to extend Scalar or use the derived subclass parameter and
    expect the same implementation class everywhere.

    So I'm going to end up with just Point<S extends Scalar<S>, T extends
    Point<S, T>>, Matrix<S extends Scalar<S>, T extends Matrix<S, T>>, etc.
    and perhaps derive specialized classes such as Point2D, Point3D,
    Matrix2X3, and so on. The latter can even just use the any-dimensional
    implementation to do everything while defining constructors that only
    generate appropriate-dimensioned objects. It'll have to be by
    containment rather than extension, due to the covariant argument types
    on some of the methods, of course, and to avoid having to cast to the
    covariant return type even on the rest. The inner instance of the
    generalized can be invoked and a new instance of the self type
    constructed to wrap it and returned.
     
    John Ersatznom, Jan 8, 2007
    #2
    1. Advertising

  3. John Ersatznom

    Chris Uppal Guest

    Re: Peculiar generics problem with static factory method (solved, but interesting and maybe instructional)

    John Ersatznom wrote:

    > > @SuppressWarnings("unchecked")
    > > public static <S extends Scalar<S>, D extends Dimension, T extends
    > > Point<S, D, T>> Point<S, D, T> getPoint (S component, D dim) {

    >
    > I think I'm going to be dumping the use of marker classes to do static
    > dimension match checking. Between the proliferation of dubious casts and
    > @SuppressWarnings usage, as well as screwy temporaries, it is making the
    > code less readable and maintainable (and maybe even correct?) instead of
    > more.


    Seems like a good idea to me.

    I had been intending to post something to the effect that the generified
    declaration was effectively unreadable (even with improved layout), and
    probably incomprehensible once decoded. Sort of a type-system-level analogue
    of code like:

    i = ++i;

    (and similar abominations) in that the compiler would understand it (modulo
    bugs), but few programmers would, and fewer still would want to have to.

    -- chris
     
    Chris Uppal, Jan 8, 2007
    #3
  4. Re: Peculiar generics problem with static factory method (solved,but interesting and maybe instructional)

    Chris Uppal wrote:
    > John Ersatznom wrote:
    >
    >
    >>>@SuppressWarnings("unchecked")
    >>>public static <S extends Scalar<S>, D extends Dimension, T extends
    >>>Point<S, D, T>> Point<S, D, T> getPoint (S component, D dim) {

    >>
    >>I think I'm going to be dumping the use of marker classes to do static
    >>dimension match checking. Between the proliferation of dubious casts and
    >>@SuppressWarnings usage, as well as screwy temporaries, it is making the
    >>code less readable and maintainable (and maybe even correct?) instead of
    >>more.

    >
    >
    > Seems like a good idea to me.
    >
    > I had been intending to post something to the effect that the generified
    > declaration was effectively unreadable (even with improved layout), and
    > probably incomprehensible once decoded. Sort of a type-system-level analogue
    > of code like:
    >
    > i = ++i;
    >
    > (and similar abominations) in that the compiler would understand it (modulo
    > bugs), but few programmers would, and fewer still would want to have to.


    Yeah. The fly in the ointment is that instead of just writing

    public class Four extends Dimension {
    public static final FOUR = new Four();
    private Four () { super(4); }
    private Object readResolve() { return FOUR; }
    }

    and getting compile-time-typesafe four-D vectors, 4xX and Xx4 matrices,
    and so forth for free, they end up having to write a Vector4D class,
    matrix classes for every Xx4 and 4xX combination ... to get the same
    level of typesafety. At least I can have AbstractFixedSizeVector<S
    extends Scalar<S>, D extends AbstractFixedSizeVector<S, D>> for them to
    extend and only have to write the constructors, and the like.
     
    John Ersatznom, Jan 8, 2007
    #4
    1. Advertising

Want to reply to this thread or ask your own question?

It takes just 2 minutes to sign up (and it's free!). Just click the sign up button to choose a username and then you can ask your own questions on the forum.
Similar Threads
  1. Matthias Kaeppler
    Replies:
    22
    Views:
    961
    Thomas G. Marshall
    May 24, 2005
  2. Replies:
    3
    Views:
    1,726
    Roedy Green
    Sep 17, 2005
  3. Medi Montaseri
    Replies:
    17
    Views:
    879
    Medi Montaseri
    Sep 3, 2003
  4. Michael Bacarella
    Replies:
    26
    Views:
    1,354
    harri
    Nov 20, 2007
  5. C#
    Replies:
    4
    Views:
    413
Loading...

Share This Page