style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">

Problema usando Arrays.sort( arreglo, comparator ) con un generics

Alguien que sepa más de generics que yo ayudeme con lo siguiente:

Estoy tratando de crear un método que a su vez llame a  Arrays.sort y quiero que este método mismo sea generico. El problema se presenta cuando intento crear una instancia de comparator concreto porque siempre me sale alguna variante del siguente error:

Generics.java:15: cannot find symbol
symbol  : method sort(java.lang.Comparable[],java.util.Comparator<T>)
location: class java.util.Arrays
                Arrays.sort(array,  c);
                      ^
1 error

Por lo pronto le di la vuelta con un mega cast, pero me gustaría saber como hacerle para no necesitarlo.

Les dejo el código relevante para reproducir el error:

import java.util.*;
abstract class Generics<T1,T2> {

  public abstract  void run( T1 a , T2 b );

  public static <T> void sort( Comparable[] array, final Generics<T,T> g  ) {

    Comparator<T> c = new Comparator<T>() {
      public int compare(T o1, T o2) {
        g.run(o1,o2);
        return 1;
      }
    };
    Arrays.sort(array,
      /* how can I get rid of this cast? */
      (Comparator<? super Comparable>)
      /* and use only */ c);
  }

  public static void main( String ... args ) {
    Generics.sort( args, new Generics<String,String>() {
      public void run( String a, String b ) {
        System.out.println( "Irrelevant");
      }
    });
  }
}

Saludos.

Update... ya me respondieron en stackoverflow :) :) jejej si alguién quiere comentar de todas formas adelante.

Opciones de visualización de comentarios

Seleccione la forma que prefiera para mostrar los comentarios y haga clic en «Guardar las opciones» para activar los cambios.
Imagen de ezamudio

Comparable

Comparable también es una interfaz genérica sin embargo no veo que le pongas nada...

El método que quieres usar, según yo, es Arrays.sort(T[], Comparator<? super T> pero le pasas como argumentos un Comparable[] y un Comparator<T> (que por lo que veo lo creas internamente como clase anónima).

El código que pusiste no genera error, como dices por el megacast, que quitándolo se genera el mismo error de nuevo.

Lo que yo hice para que tu código compile fue simplemente cambiar la declaración del primer parámetro de sort para que quede sort(T[] array, final Generic<T,T> g) y con eso puedes quitar el cast y compila y corre bien.

Ahora lo interesante: por qué funciona así? pues simplemente porque entonces ya usas el método Array.sort(T[], Comparator<? super T>). La otra opción era declarar tu Comparator como Comparator<Comparable> pero entonces tienes que cambiar un montón de cosas y limitas tu clase a usar realmente puros Comparable (sin que los marques como genéricos a su vez):

abstract class Generics<T1,T2> {
  public abstract  void run( T1 a , T2 b );
  public static void sort( Comparable[] array, final Generics<Comparable,Comparable> g  ) {
    Comparator<Comparable> c = new Comparator<Comparable>() {
      public int compare(Comparable o1, Comparable o2) {
        g.run(o1,o2);
        return 1;
      }
    };
    Arrays.sort(array,
      /* how can I get rid of this cast? */
      /* and use only */ c);
  }
  public static void main( String ... args ) {
    Generics.sort( args, new Generics<Comparable,Comparable>() {
      public void run( Comparable a, Comparable b ) {
        System.out.println( "Irrelevant");
      }
    });
  }
}

Queda mucho más simple usando directamente T:

import java.util.*;
abstract class Generics<T1,T2> {
  public abstract  void run( T1 a , T2 b );
  public static <T> void sort( T[] array, final Generics<T,T> g  ) {
    Comparator<T> c = new Comparator<T>() {
      public int compare(T o1, T o2) {
        g.run(o1,o2);
        return 1;
      }
    };
    Arrays.sort(array, c);
  }
  public static void main( String ... args ) {
    Generics.sort( args, new Generics<String, String>() {
      public void run(String a, String b) {
        System.out.println( "Irrelevant");
      }
    });
  }
}

Hay explicaciones más completas de generics en la documentación oficial.

Ahora, voy a hacer un comentario que necesita un disclaimer gigante para que no sea malinterpretado por ti o por el resto de la comunidad, así que aquí va el disclaimer gigante: Digo esto con la mejor de las intenciones, no como una crítica venenosa o de alguien de nada más critica trabajo ajeno sin aportar nada, ni estoy insinuando que no sepas lo que haces ni nada por el estilo:

Estás diseñando un lenguaje de programación y tienes dudas medio básicas de generics en Java, creo que refuerzas un poco lo que decíamos bferro y yo cuando salió el anuncio inicial de Ryz: hay que tener mucho conocimiento teórico y un diseño formal muy bien definido para hacer un lenguaje de programación.

Ya. Ese era el comentario. Ahora deja me pongo mi impermeable porque seguro que con todo y el disclaimer gigante, me va a caer una avalancha de mierda. Sé que no te lo vas a tomar personal pero pues estamos en internet, desde antes de oprimir el botón para enviar el comentario ya me estoy preparando...

Imagen de ezamudio

stackoverflow

Ah, te contestaron lo mismo que yo, al mismo tiempo, cool...

Diablos!!!... hay un

Diablos!!!... hay un pequeñisimo detalle que olvide poner y el cual le da completo sentido a la pregunta.

La firma de run es:

public abstract void run( Comparable<T1> a , T2 b );

Y no:

public abstract void run( T1  a , T2 b );

Como puse inicialmente.

En mi intento de no decir: "Ahí les va TOOODO mi código busquenle" le quite demasiadas cosas. By bad. Y claro tú no podías haberlo adivinado porque no tienes un casco visor de código remoto o sí??? :)

La respuesta de usar solo T pues si, es super básica. De hecho lo primero que intenté fue simplemente usar T ( no llegue hasta Comparable[] nomás porque sí )

Este es el error que sale:

H.java:7: run(java.lang.Comparable<T>,T) in Generics<T,T> cannot be applied to (T,T)
        g.run(o1,o2);
         ^
H.java:14: <anonymous Generics$2> is not abstract and does not override abstract method run(java.lang.Comparable<java.lang.String>,java.lang.String) in Generics
    Generics.sort( args, new Generics<String, String>() {
                                                        ^
2 errors

Y como bien dices usar puros "Comparables" en ocioso porque no se puede instanciar con nada, también anduve por ahí un rato.

La respuesta correcta es la que pusieron en SO.

public static <T extends Comparable<T>> void sort( T[] array, final Generics<T,T> g  ) {

Es decir, definir T como una cosa que hereda de Comparable y con eso ya se puede usar por ejemplo Strings. Lo interesante es que Paŭlo Ebermann lo contestó así, con el mismo código de ejemplo, la clave está en que mi arreglo debía de ser de comparables y al usar solamente T eso se ignora esta intención por completo, luego entonces, no era tan básica como ves.

Ahora sobre la segunda observación, te agradezco muchísimo el disclaimer, porque le dá totalmente sentido a la intención ( ahh esta interweb tan impersonal caray ).

Esa es precisamente una de las razones por las cuales estoy haciendo Ryz y es un poco de lo que voy a hablar este viernes en el Hackerrom ( Gooool! ) . Nadie nace sabiendo todas las cosas y todos estamos siempre en posibilidad de aprender aún más, es decir, nuestra capacidad de aprendizaje parece ser infinita. En mi caso en particular aprendo mucho más haciendo que simplemente leyendo ( sobre todo con este tipo de cosas ) y definitivamente no quería esperar a tener todo ese conocimiento para empezar a hacer algo.

Es precisamente lo que le comenté a alguien que posteo lo de una librería para manipulación de fechas. Le dije "Que bueno que haces esto para aprender!" porque por ejemplo yo, anteriormente había hecho un mini ORM y así logré entender muchísimo de como funcionan estas chunches. Pero en esa ocasión nuestro compañero se molestó y su amigo lo defendió diciendo que él era el mejor programador que conocía ( en mi opinión conicía muy pocos ).

Entonces Ryz es mi oportunidad de aprender haciendo. No te imaginas la cantidad de cosas que he aprendido en el último año, sobre compiladores, lenguajes, y demás menesteres.

Coincido contigo en que se necesita un montón de conocimiento para hacer una de estas cosas bien ( y hasta para hacerlas mal ), te agradezco de verdad el comentario ( y creo que aún más el disclaimer je je je ) . Esta es entonces pues mi forma de adquirir ese conocimiento!

:)

Imagen de ezamudio

detallín

Ah pues sí cambia bastante el problema con run(Comparable<T1>, T2). En fin.

Recuerdo bien ese foro que dices donde el mejor programador del mundo vino a iluminarnos con sus rutinas para manejo de fechas. Alguna vez leí (en un blog o donde sea, no recuerdo, no importa) que en el mundo del software libre es muy importante publicar desde el principio las cosas, no esperar a tener una versión ya funcional para subirla al repositorio, porque entonces muchos proyectos se quedan en 0. Pero la bronca es que para hacer eso, subir las primeras versiones de código, hay que estar dispuesto a aceptar críticas buenas y malas (es internet), con la debida cantidad de sal en cada caso, y pues eso requiere cierto carácter. Qué bueno que lo tienes.

:")

style="display:inline-block;width:728px;height:90px"
data-ad-client="ca-pub-5164839828746352"
data-ad-slot="7563230308">