2010-04-28 23 views
14

¿Por qué este código no puede compilarse, pero se compila correctamente cuando elimino el comentario de la línea indicada? (Estoy usando Scala 2.8 todas las noches). Parece que llamar explícitamente al string2Wrapper le permite ser utilizado implícitamente desde ese momento.¿Por qué esta llamada explícita de un método de Scala permite que se resuelva implícitamente?

class A { 
    import Implicits.string2Wrapper 
    def foo() { 
    //string2Wrapper("A") ==> "B" // <-- uncomment 
    } 
    def bar() { 
    "A" ==> "B" 
    "B" ==> "C" 
    "C" ==> "D" 
    } 
    object Implicits { 
    implicit def string2Wrapper(s: String) = new Wrapper(s) 
    class Wrapper(s: String) { 
     def ==>(s2: String) {} 
    } 
    } 
} 

Editar: Gracias por las respuestas hasta el momento, que incluyen un puntero al comentario de Martin Odersky,

"Una conversión implícita y sin tipo de resultado explícito es visible sólo en el texto tras su propia definición. De esta forma, evitamos los errores de referencia cíclicos ".

Todavía estaría interesado en descubrir 1) ¿cuál es el peligro de "errores de referencia cíclicos" ?, y 2) ¿Por qué una llamada explícita hace alguna diferencia?

Respuesta

19

Asignando explícitamente el tipo de devolución de string2Wrapper corrige el problema.

class A { 
    import Implicits._ 

    def bar() {  
    "A" ==> "B" 
    "B" ==> "C" 
    "C" ==> "D" 
    } 
    object Implicits { 
    implicit def string2Wrapper(s: String): Wrapper = new Wrapper(s) 
    class Wrapper(s: String) { 
     def ==>(s2: String) {} 
    } 
    } 
} 

Definición Implicits antes bar también funciona:

class A { 
    object Implicits { 
    implicit def string2Wrapper(s: String) = new Wrapper(s) 
    class Wrapper(s: String) { 
     def ==>(s2: String) {} 
    } 
    } 

    import Implicits._ 

    def bar() {  
    "A" ==> "B" 
    "B" ==> "C" 
    "C" ==> "D" 
    } 
} 

Si tiene que depender de una conversión implícita se define a continuación dentro del ámbito actual, asegúrese de anotar el tipo de retorno. Seguramente esto ha aparecido en las listas de correo antes, y se puede esperar un comportamiento en lugar de un error. Pero no puedo localizarlo en este momento. Supongo que la llamada explícita en foo desencadena la inferencia de tipo del tipo de devolución de bar, que luego es válida al escribir los contenidos de bar.

ACTUALIZACIÓN

¿Cuál es el peligro de que el error de referencia cíclica?

El cuerpo del método implícito puede llamar al método que requiere la conversión implícita. Si ambos tienen un tipo de devolución inferida, estás en un callejón sin salida. Esto no se aplica en su ejemplo, pero el compilador no intenta detectar esto.

¿Por qué una llamada explícita hace la diferencia?

La llamada explícita a principios desencadena la inferencia de tipos del tipo de retorno del método implícito. Aquí está la lógica en Implicits.isValid

sym.isInitialized || 
     sym.sourceFile == null || 
     (sym.sourceFile ne context.unit.source.file) || 
     hasExplicitResultType(sym) || 
     comesBefore(sym, context.owner) 

ACTUALIZACIÓN 2

Esta reciente fallo parece relevante: https://lampsvn.epfl.ch/trac/scala/ticket/3373

+0

Es (se supone que debe ser) spec'ed. Paulp ha desenterrado un boleto a tal punto muy recientemente. Déjame ver si yo no lo encuentro ... –

+5

aquí: https://lampsvn.epfl.ch/trac/scala/ticket/801 –

3

Si pones object Implicits primera, funciona. Esto me parece un error en la lógica para hacer múltiples pasos de compilación; asume que puede escaparse sin saber realmente string2Wrapper al compilar bar.Mi conjetura es que si lo usa, sabe que no puede salirse con no saber qué string2Wrapper realmente es, en realidad compila Implicits, y luego se da cuenta de que ==> se define implícitamente en cadena.

Editar: Sobre la base de lo que ha escrito retronym, tal vez es una "característica" no es un error. ¡Todavía me parece desatinado!

12

Si se acaba de ooooone las noches más tarde que en vez habría visto el mensaje de error añadí ayer.

<console>:11: error: value ==> is not a member of java.lang.String 
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type 
      "A" ==> "B" 
     ^
<console>:12: error: value ==> is not a member of java.lang.String 
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type 
      "B" ==> "C" 
     ^
<console>:13: error: value ==> is not a member of java.lang.String 
Note: implicit method string2Wrapper is not applicable here because it comes after the application point and it lacks an explicit result type 
      "C" ==> "D" 
     ^
Cuestiones relacionadas