2010-07-18 31 views
6

estoy tratando de crear una instancia de un rasgo utilizando este método¿Cómo creo una instancia de un rasgo en un método genérico en scala?

val inst = new Object with MyTrait 

Esto funciona bien, pero me gustaría pasar esta creación de una función de generador, es decir.

object Creator { 
    def create[T] : T = new Object with T 
} 

Obviamente estoy va a necesitar el manifiesto para fijar de alguna manera los problemas de tipo de borrado, pero antes de llegar a esto, correr a 2 preguntas:

  1. Incluso con un manifiesto implícita , Scala todavía exige que T sea un rasgo. ¿Cómo agrego una restricción para crear [T] para que T sea un rasgo?

  2. Si he optado por utilizar el método Class.newInstance para crear la instancia de forma dinámica en lugar de utilizar "nueva", ¿cómo voy a especificar el "con" en el "nuevo objeto con T"? ¿Es posible crear dinámicamente nuevos tipos de mezclas de hormigón en tiempo de ejecución?

Respuesta

8

No puede hacer esto (incluso con un Manifiesto). El código new Object with T implica la creación de una nueva clase anónima que representa la combinación de Object with T. Para pasar esto a su función create, tendría que generar esta nueva clase (con un nuevo bytecode) en tiempo de ejecución, y Scala no tiene capacidad para generar una nueva clase en tiempo de ejecución.

Una estrategia podría ser intentar transferir la funcionalidad especial del método de fábrica al constructor de la clase y luego usar el constructor directamente.

Otra posible estrategia es crear funciones de conversión (implícitas o no) para los rasgos que le interesan usar con esta clase.

+0

Esto parece ser una limitación interesante del lenguaje, pero no veo una razón por la que no se pueda solucionar con un nuevo soporte de mixin "Dinámico" en Scala. El código de característica ya está disponible como métodos estáticos, por lo que la búsqueda de linealización podría calcularse en tiempo de ejecución en lugar de procesarse en el código de clase bytecode. Entonces solo necesitarías agregar la verificación del tipo de tiempo de ejecución para que funcione "asInstanceOf". – ACyclic

14

No estoy seguro de cuál es la motivación para su pregunta, pero podría considerar pasar una fábrica para T como un parámetro implícito. Esto se conoce como el uso de las clases de tipo o polimorfismo ad-hoc.

object Test extends Application { 
    trait Factory[T] { 
    def apply: T 
    } 
    object Factory { 
    /** 
    * Construct a factory for type `T` that creates a new instance by 
    * invoking the by-name parameter `t` 
    */ 
    def apply[T](t: => T): Factory[T] = new Factory[T] { 
     def apply = t 
    } 
    } 

    // define a few traits... 
    trait T1 
    trait T2 

    // ...and corresponding instances of the `Factory` type class. 
    implicit val T1Factory: Factory[T1] = Factory(new T1{}) 
    implicit val T2Factory: Factory[T2] = Factory(new T2{}) 

    // Use a context bound to restrict type parameter T 
    // by requiring an implicit parameter of type `Factory[T]` 
    def create[T: Factory]: T = implicitly[Factory[T]].apply 

    create[T1] 
    create[T2] 

} 

En el otro extremo del espectro, que podría invocar el compilador en tiempo de ejecución, como se detalla en this answer a la pregunta "mixin dinámica en Scala -? ¿Es posible".

+0

Gracias, puede que tenga que usar este método. Mi caso de uso es Java Proxy. Quiero escribir una biblioteca que sea remotable. Por lo tanto, necesito definir interfaces para todas mis clases, lo cual es un dolor ya que quiero exponer todo. Una solución es escribir todo como un rasgo, luego obtengo la definición de la interfaz de forma gratuita. El propósito de la función de creación es crear una instancia de un rasgo en el lado "concreto" de la conexión proxy. – ACyclic

Cuestiones relacionadas