swing scala pattern-matching type-erasure

Eventos de Swing seguros de tipo: "La referencia externa en este tipo de prueba no se puede verificar en tiempo de ejecuciĆ³n"



scala pattern-matching (1)

Estoy implementando un componente Swing y quiero superar la falta de #### del Reactor . Así que pensé que esto funcionaría:

trait Foo[A] extends scala.swing.Publisher { final case class Bar(parent: Vector[A], children: A*) extends scala.swing.event.Event } trait Test { val foo: Foo[Int] foo.reactions += { case foo.Bar(parent, children) => { println(parent.sum - children) } } }

Desafortunadamente eso me da dos advertencias de compilación:

The outer reference in this type test cannot be checked at run time. final case class Bar(parent: Vector[A], children: A*) extends scala.swing.event.Event ^ The outer reference in this type test cannot be checked at run time. case foo.Bar(parent, children) => { ^

¿Debo ignorar estas advertencias? ¿Puedo suprimirlos? ¿Debo cambiar el diseño?


En Scala, las clases internas son "dependientes de la trayectoria".

Usaré tu código como ejemplo. Si tiene dos Foo[Int] s, llamados foo y bar , entonces foo.Bar es un tipo diferente a bar.Bar . Tenga en cuenta que esto difiere de la idea de Java de clases internas, donde foo.Bar y bar.Bar son del mismo tipo.

En cualquier caso, la JVM no admite clases internas directamente, por lo tanto, tanto en Java como en Scala, la clase Bar compila en una clase JVM llamada Foo$Bar . Las instancias de clases internas casi siempre contienen una referencia a su propietario, la "referencia externa".

Ahora, cuando tiene una coincidencia de patrón en un tipo dependiente de la ruta (como el de su código), el compilador de Scala producirá un código de bytes que hace dos cosas: verificará la clase (así comprobará que el objeto que recibió) es una instancia de Foo$Bar ), y verificará la referencia externa (por lo tanto, verificará que la referencia externa del objeto recibido sea foo ).

Sin embargo, en su código, el compilador no puede encontrar una manera de verificar la referencia externa, porque ha declarado que su clase interna es definitiva.

Por lo tanto, si ignora la advertencia, su patrón coincidirá con todas las instancias de Foo$Bar , incluso si no pertenecen a foo . Tendrás una mejor idea que yo de si esto será un problema.

O, puedes arreglarlo haciendo que tu clase interna no sea final.

Pd, no estoy completamente seguro de por qué el compilador de Scala no puede verificar las referencias externas en las clases internas finales, pero he encontrado que si una clase interna es definitiva, entonces outer$ es privado, mientras que si no es final, outer$ es público. Podría valer la pena echar un vistazo en el interior del compilador, para averiguar por qué esto es.

Actualizar

Resulta que este es un problema conocido - SI-4440 . El compilador Scala elimina las referencias externas para las clases internas finales, si no se usan (lo cual es vagamente legítimo, ya que tampoco hay posibilidad de que las subclases las usen). Una consecuencia positiva de esto es que las clases externas pueden ser recolectadas con basura mientras las clases internas todavía están en uso, por lo que los desarrolladores de Scala son reacios a reintroducir referencias externas por temor a introducir fugas de memoria.