5 votes

Génériques Scala : Int non conforme à Comparable ?

Les déclarations Scala suivantes sont correctes :

trait Base[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] {
    // ...
}

trait Meta[B <: Base[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Ordered[Meta[_,_,_]] {
    // ...
}

trait BaseWithID[B <: BaseWithID[B,M,ID], M <: Meta[B,M,ID], ID <: Comparable[ID]] extends Base[B,M,ID] with Ordered[B] {
    // ...
}

trait BaseWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends BaseWithID[B,M,ID] {
    // ...
}

trait MetaWithIntID[B <: BaseWithIntID[B,M,ID], M <: MetaWithIntID[B,M,ID], ID <: Comparable[ID]] extends Meta[B,M,ID] {
    // ...
}

Mais les deux suivants ne le sont pas :

trait BaseWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends BaseWithID[B,M,Int] {
    // ...
}

trait MetaWithIntID[B <: BaseWithIntID[B,M], M <: MetaWithIntID[B,M]] extends Meta[B,M,Int] {
    // ...
}

La différence est que j'ai supprimé le paramètre de type ID dans BaseWithIntID et MetaWithIntID, et que j'ai spécifié Int explicitement dans leurs traits de base respectifs. Mais cela ne compile pas, alors cela signifie-t-il que Int n'est pas comparable en Scala ? Si c'est le cas, qu'est-ce que je fais de mal ? J'ai essayé Ordered au lieu de Comparable, et cela n'a fait aucune différence.

J'utilise Eclipse et, comme d'habitude, les messages d'erreur ne m'aident pas :

type arguments [B,M,Int] do not conform to trait BaseWithID's type parameter bounds [B <: BaseWithID[B,M,ID],M <: Meta[B,M,ID],ID <: java.lang.Comparable[ID]]

Il indique simplement que quelque chose ne va pas, mais ne précise pas quel type de paramètre est incorrect, ni pourquoi. En regardant cette question J'ai pensé que je pourrais essayer "ID <% Comparable[ID]" à la place, mais ce n'est pas légal dans une déclaration de trait.

En fait, cela ne fonctionne pas non plus (avec le même message d'erreur) :

trait TestBase extends BaseWithID[TestBase,TestMeta,Int]

trait TestMeta extends Meta[TestBase,TestMeta,Int]

10voto

Didier Dupont Points 18256

Int n'est en effet pas comparable en scala, certainement parce qu'il est en fait implémenté comme java int pas java.lang.Integer . Je ne suis pas sûr que cela aurait été impossible, C# struct (types de valeurs) peuvent implémenter des interfaces, mais cela n'est pas fait ici.

Ce que vous faites habituellement, c'est dire qu'il y a un Ordering disponibles dans la portée implicite pour votre type d'identification, avec ID : Ordering .

Un exemple simple :

import Ordering.Implicits._
def max[A : Ordering](x: A, y: A) : A = if (x > y) then x else y

Cela revient à passer un Ordering (qui est la même chose qu'un java.util.Comparator ) à la fonction. En effet, la déclaration

def max[A : Ordering](x: A, y: A)

se traduit par

def max[A](x: A, y: A)(implicit ev: Ordering[A])

ev est un nouveau nom. Si A : Ordering apparaît sur la définition de la classe plutôt que de la méthode, comme dans votre code, cela se traduit par un paramètre implicite au constructeur, qui sera gardé dans un champ si nécessaire, et sera disponible en portée implicite dans la classe. Ceci est plus flexible que de forcer A à être Comparable ( Ordered en scala) car il peut être utilisé sur une classe qui n'est pas la vôtre et qui n'a pas implémenté Comparable. Vous pouvez aussi choisir entre différents Odering sur la même classe, ne serait-ce qu'en inversant celui par défaut : il existe un def reverse : Ordering méthode sur Ordering qui fait exactement cela.

Du côté négatif, il est peu probable que la VM soit en mesure de mettre en ligne l'appel à la méthode de comparaison, mais ce n'était pas non plus le cas avec une méthode d'interface dans un générique.

Les types qui mettent en œuvre Comparable<T> en java obtient automatiquement un Ordering dans une portée implicite en vertu d'une méthode implicite ( ordered ) dans l'objet Ordering . A java Comparator<T> peut également être converti en un Ordering ( Ordering.comparatorToOrdering ).

L'importation de Ordering.Implicits._ vous permet d'avoir l'agréable x > y syntaxe, lorsqu'un Ordering[A] est dans une portée implicite.

0voto

Sebastien Diot Points 2237

La réponse à la question "Cela signifie-t-il que Int n'est pas comparable en Scala ?" est évidemment OUI, car si je remplace Int par java.lang.Integer, cela compile sans erreur. Le problème est alors que je dois créer un objet wrapper à chaque fois que j'accède à l'ID, ce qui va arriver souvent et donc être coûteux.

Je voulais spécifier que l'ID est Comparable/Ordered afin de pouvoir rendre la BaseWithID elle-même ordonnée, et y définir explicitement la méthode de comparaison en utilisant les ID comparables.

La solution, pour le moment, semble être de ne pas spécifier que l'ID est ordonné, et de laisser la classe concrète implémenter la comparaison elle-même, au lieu de l'implémenter une seule fois dans le trait. Quelqu'un a-t-il une meilleure solution ?

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X