136 votes

Qu'est-ce qu'un manifeste en Scala et quand en avez-vous besoin ?

Depuis Scala 2.7.2, il existe un élément appelé Manifest qui est une solution de contournement de l'effacement de type de Java. Mais comment Manifest et pourquoi / quand devez-vous l'utiliser ?

Le billet de blog Manifestes : Types réifiés de Jorge Ortiz en explique une partie, mais il n'explique pas comment l'utiliser avec limites du contexte .

De même, qu'est-ce que ClassManifest quelle est la différence avec Manifest ?

J'ai du code (qui fait partie d'un programme plus large, je ne peux pas facilement l'inclure ici) qui a quelques avertissements concernant l'effacement de type ; je pense que je peux les résoudre en utilisant les manifestes, mais je ne suis pas sûr de savoir exactement comment.

2 votes

Une discussion a eu lieu sur la liste de diffusion à propos de la différence entre Manifest et ClassManifest, voir scala-programming-language.1934581.n4.nabble.com/

0 votes

204voto

Mitch Blevins Points 7646

Le compilateur connaît plus d'informations sur les types que le moteur d'exécution de la JVM ne peut facilement représenter. Un manifeste est un moyen pour le compilateur d'envoyer un message inter-dimensionnel au code au moment de l'exécution concernant les informations sur les types qui ont été perdues.

Il n'est pas certain qu'un manifeste puisse corriger les erreurs que vous constatez sans avoir plus de détails.

Une utilisation courante des Manifests consiste à faire en sorte que votre code se comporte différemment en fonction du type statique d'une collection. Par exemple, que se passerait-il si vous vouliez traiter une List[String] différemment des autres types de List :

 def foo[T](x: List[T])(implicit m: Manifest[T]) = {
    if (m <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

  foo(List("one", "two")) // Hey, this list is full of strings
  foo(List(1, 2)) // Non-stringy list
  foo(List("one", 2)) // Non-stringy list

Une solution basée sur la réflexion impliquerait probablement d'inspecter chaque élément de la liste.

Le context bound semble le mieux adapté à l'utilisation des classes de type en Scala, et est bien expliqué ici par Debasish Ghosh : http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Les limites de contexte peuvent aussi simplement rendre les signatures de méthodes plus lisibles. Par exemple, la fonction ci-dessus pourrait être réécrite en utilisant des bornes de contexte comme suit :

  def foo[T: Manifest](x: List[T]) = {
    if (manifest[T] <:< manifest[String])
      println("Hey, this list is full of strings")
    else
      println("Non-stringy list")
  }

26voto

Mechanical snail Points 8589

Un manifeste était destiné à réifier les types génériques qui sont effacés pour être exécutés sur la JVM (qui ne prend pas en charge les types génériques). Cependant, ils présentaient de sérieux problèmes : ils étaient trop simplistes et incapables de supporter pleinement le système de types de Scala. Ils étaient donc obsolète dans Scala 2.10, et sont remplacés par TypeTag (qui sont essentiellement ce que le compilateur Scala lui-même utilise pour représenter les types, et qui supportent donc pleinement les types Scala). Pour plus de détails sur la différence, voir :

En d'autres termes

quand en avez-vous besoin ?

Avant 2013-01-04, lors de la sortie de Scala 2.10 .

0 votes

Elle n'est pas encore dépréciée (mais le sera), car la réflexion en Scala est encore expérimentale dans la version 2.10.

0 votes

Avant le 2013-01-04, ou si vous utilisez une API qui en dépend.

25voto

VonC Points 414372

La réponse n'est pas complète, mais en ce qui concerne la différence entre Manifest y ClassManifest Vous trouverez un exemple dans la rubrique Scala 2.8 Array papier :

La seule question qui subsiste est de savoir comment mettre en œuvre la création de tableaux génériques. Contrairement à Java, Scala permet la création d'une instance de nouveau Array[T] donde T est un paramètre de type. Comment cela peut-il être mis en œuvre, étant donné qu'il n'existe pas de représentation uniforme des tableaux en Java ?

La seule façon d'y parvenir est d'exiger des informations d'exécution supplémentaires qui décrivent le type T . Scala 2.8 dispose d'un nouveau mécanisme pour cela, qui s'appelle un Manifeste . Un objet de type Manifest[T] fournit des informations complètes sur le type T .
Manifest les valeurs sont généralement transmises dans des paramètres implicites ; et le compilateur sait comment les construire pour les types statiquement connus T .

Il existe également un forme plus faible nommée ClassManifest qui peut être construit en ne connaissant que la classe de premier niveau d'un type, sans nécessairement connaître tous ses types d'arguments .
C'est ce type d'informations d'exécution qui est nécessaire pour la création de tableaux.

Exemple :

Il faut fournir cette information en passant un ClassManifest[T] i en tant que paramètre implicite :

def  tabulate[T](len:Int,  f:Int=>T)(implicit m:ClassManifest[T]) =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 

En guise d'abréviation, un contexte lié1 peut être utilisé pour le paramètre de type T au lieu de cela,

(Voir cette Question à titre d'illustration )

, en donnant :

def  tabulate[T:    ClassManifest](len:Int,  f:Int=>T)  =  { 
  val  xs  =  new  Array[T](len) 
  for   (i  <- 0  until   len)  xs(i)   = f(i) 
  xs 
} 

Lors de l'appel d'une tabulation sur un type tel que Int ou String ou List[T] le compilateur Scala peut créer un manifeste de classe à passer comme argument implicite à tabulate.

1voto

Tomer Ben David Points 36

Vérifions également manifest en scala sources ( Manifest.scala ), nous voyons :

Manifest.scala:
def manifest[T](implicit m: Manifest[T])           = m

Ainsi, en ce qui concerne l'exemple de code suivant :

def foo[A](somelist: List[A])(implicit m: Manifest[A]): String = {
  if (m <:< manifest[String]) {
    "its a string"
  } else {
    "its not a string"
  }
}

nous pouvons constater que le manifest function recherche un m: Manifest[T] qui répond à l'objectif de type parameter que vous fournissez dans notre code d'exemple, c'était manifest[String] . Ainsi, lorsque vous appelez quelque chose comme :

if (m <:< manifest[String]) {

vous vérifiez si le implicit m que vous avez défini dans votre fonction est de type manifest[String] et en tant que manifest est une fonction de type manifest[T] il rechercherait un manifest[String] et il trouverait s'il existe un tel implicite.

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