2010-07-09 14 views
116

Desde Scala 2.7.2 hay algo llamado Manifest que es una solución para el borrado de tipos de Java. Pero, ¿cómo funciona Manifest exactamente y por qué/cuándo es necesario usarlo?¿Qué es un Manifiesto en Scala y cuándo lo necesitas?

La entrada de blog Manifests: Reified Types por Jorge Ortiz explica algo de él, pero no explica cómo usarlo junto con context bounds.

Además, ¿cuál es la diferencia con Manifest?

Tengo un código (parte de un programa más grande, no se puede incluir fácilmente aquí) que tiene algunas advertencias con respecto a la borradura de tipo; Sospecho que puedo resolver estos mediante el uso de manifiestos, pero no estoy seguro exactamente cómo.

+2

Ha habido una discusión en la lista de correo acerca de la diferencia Manifiesto/ClaseManifiesto, vea http://scala-programming-language.1934581.n4.nabble.com/What-s-the-difference-between-ClassManifest- and-Manifest-td2125122.html –

+0

Vea también: [Scala: ¿Qué es un TypeTag y cómo lo uso?] (http://stackoverflow.com/questions/12218641/scala-what-is-a-typetag-and -how-do-i-use-it) – Jesper

Respuesta

174

El compilador conoce más información acerca de los tipos que el tiempo de ejecución JVM puede representar fácilmente. Un Manifiesto es una forma de que el compilador envíe un mensaje interdimensional al código en tiempo de ejecución sobre la información de tipo que se perdió.

Esto es similar a cómo los Kleptonianos han dejado mensajes codificados en los registros fósiles y el ADN "basura" de los humanos. Debido a las limitaciones de la velocidad de la luz y los campos de resonancia gravitacional, no pueden comunicarse directamente. Pero, si sabe cómo sintonizar su señal, puede beneficiarse de maneras que no puede imaginar, desde decidir qué comer para el almuerzo o qué número de lotería jugar.

No está claro si un Manifest beneficiaría los errores que está viendo sin conocer más detalles.

Un uso común de Manifests es que su código se comporte de forma diferente en función del tipo estático de una colección. Por ejemplo, ¿qué pasaría si se quería tratar de una lista [String] diferente a otros tipos de una lista:

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 

Una solución basada en la reflexión a esto probablemente implicará la inspección de cada elemento de la lista.

Un contexto con destino parece más adecuado para el uso de tipo-clases en Scala, y está bien explicado aquí por Debasish Ghosh: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

límites de contexto también pueden simplemente hacer las firmas de los métodos más legible. Por ejemplo, la función anterior podría ser re-escrito usando los límites del contexto de esta manera:

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") 
    } 
+13

Votación hacia arriba para el caso de uso. Me gustaría tener una segunda votación para la sección de Kleptonian fuera del jardín izquierdo. – huynhjl

+8

Aha, es un mensaje interdimensional secreto del compilador de Scala ... ;-) – Jesper

+1

Kryptonians? Gran metáfora de todos modos! – kirhgoff

25

No es una respuesta completa, pero en cuanto a la diferencia entre Manifest y ClassManifest, se puede encontrar un ejemplo en el Scala 2.8 Array paper:

La única cuestión pendiente es cómo poner en práctica genérica creación de la matriz. A diferencia de Java, Scala permite una creación de instancia nueva Array[T] donde T es un parámetro de tipo. ¿Cómo se puede implementar esto, dado el hecho de que no existe una representación de matriz uniforme en Java?

La única forma de hacerlo es requiriendo información de tiempo de ejecución adicional que describa el tipo T. Scala 2.8 tiene un nuevo mecanismo para esto, que se llama Manifiesto. Un objeto del tipo Manifest[T] proporciona información completa sobre el tipo T.
Manifest los valores se pasan típicamente en parámetros implícitos; y el compilador sabe cómo construirlos para los tipos estáticamente conocidos T.

Existe también una forma más débil llamado ClassManifest que puede ser construido a partir de saber exactamente la clase de nivel superior de un tipo, y sin que sea necesario conocer todos sus tipos de argumento.
Este tipo de información de tiempo de ejecución es necesaria para la creación de matrices.

Ejemplo:

Uno tiene que proporcionar esta información haciendo pasar una ClassManifest[T] en el método como un parámetro implícito:

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 
} 

Como una forma abreviada, una context bound1 se puede utilizar en el parámetro de tipo T en su lugar,

(Ver este SO question for illustration)

, dando:

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 
} 

Al llamar tabular en un tipo como Int o String o List[T], el compilador Scala puede crear un manifiesto de clase para pasar como argumento implícito para tabular.

22

un manifiesto se pretende materializar tipos genéricos que obtener el tipo que se ha borrado a ejecutar en la JVM (que no soporta los genéricos). Sin embargo, tenían algunos problemas serios: eran demasiado simplistas y no podían soportar completamente el sistema de tipos de Scala. Por lo tanto, fueron obsoletos en Scala 2.10, y se reemplazan por TypeTag s (que son esencialmente lo que el propio compilador de Scala usa para representar tipos, y por lo tanto son totalmente compatibles con los tipos de Scala). Para más detalles sobre la diferencia, consulte:

En otras palabras

cuando lo necesita?

Antes del 2013-01-04, when Scala 2.10 was released.

+0

Todavía no está en desuso (pero lo será), ya que la reflexión de Scala aún es experimental en 2.10. – Keros

+0

Antes de 2013-01-04, o si está utilizando una API que se basa en ella. –

1

también vamos a chck cabo manifest en scala fuentes (Manifest.scala), vemos:

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

Así que en lo que respecta al siguiente código de ejemplo:

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

podemos ver que los manifestfunction búsquedas de un m: Manifest[T] implícito que satisface el type parameter que proporciona en nuestro código de ejemplo era manifest[String]. Así que cuando se llama algo así como:

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

se está comprobando si la corriente implicit m la que ha definido en su función es de tipo manifest[String] y como el manifest es una función del tipo manifest[T] sería buscar una específica manifest[String] y encontraría si hay tal implícito.

Cuestiones relacionadas