scala manifest

¿Qué es un Manifiesto en Scala y cuándo lo necesitas?



manifest (4)

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 Manifiesto beneficiará los errores que está viendo sin conocer más detalles.

Un uso común de Manifests es hacer que su código se comporte de manera diferente en función del tipo estático de una colección. Por ejemplo, ¿qué pasaría si quisiera tratar una Lista [Cadena] de manera 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ía inspeccionar cada elemento de la lista.

Un límite de contexto parece ser el más adecuado para usar clases de tipo en scala, y Debasish Ghosh lo explica bien aquí: http://debasishg.blogspot.com/2010/06/scala-implicits-type-classes-here-i.html

Los límites de contexto también pueden hacer que las firmas de métodos sean más legibles. Por ejemplo, la función anterior podría volver a escribirse utilizando los límites de contexto de la siguiente 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") }

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 el Manifest exactamente y por qué / cuándo necesita usarlo?

La publicación del blog Manifiestos: Tipos reificados por Jorge Ortiz explica algo de esto, pero no explica cómo usarlo junto con los límites de contexto .

Además, ¿qué es ClassManifest , 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 eliminación del tipo; Sospecho que puedo resolver estos mediante el uso de manifiestos, pero no estoy seguro exactamente cómo.


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

La única pregunta restante es cómo implementar una matriz genérica. A diferencia de Java, Scala permite una instancia que crea una 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 exigir 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 de tipo Manifest[T] proporciona información completa sobre el tipo T
Manifest valores de Manifest generalmente se pasan en parámetros implícitos; y el compilador sabe cómo construirlos para los tipos T conocidos estadísticamente.

También existe una forma más débil llamada ClassManifest que se puede construir conociendo solo la clase de primer nivel de un tipo, sin conocer necesariamente todos sus tipos de argumentos .
Es este tipo de información de tiempo de ejecución lo que se requiere para la creación de matrices.

Ejemplo:

Es necesario proporcionar esta información pasando un 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, un contexto bound1 se puede utilizar en el parámetro de tipo T lugar,

(Ver esta pregunta SO para la ilustración )

, 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 a tabulate en un tipo como Int , o String , o List[T] , el compilador de Scala puede crear un manifiesto de clase para pasar como argumento implícito a tabular.


También vamos a manifest en las fuentes de scala ( Manifest.scala ), vemos:

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

Entonces con respecto 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 la function manifest busca un m: Manifest[T] implícito que satisface el type parameter usted proporciona en nuestro código de ejemplo que fue manifest[String] . Entonces cuando llamas algo así:

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

está comprobando si la implicit m actual que definió en su función es de tipo manifest[String] y como el manifest es una función de tipo manifest[T] buscaría un manifest[String] específico manifest[String] y encontraría si hubiera es tal implícito


Un Manifiesto tenía la intención de reificar los tipos genéricos que se borran por el tipo para que se ejecuten en la JVM (que no es compatible con 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, quedaron 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 completamente compatibles con los tipos de Scala). Para más detalles sobre la diferencia, ver:

En otras palabras

¿cuando lo necesitas?

Antes de 2013-01-04, cuando se lanzó Scala 2.10 .