2010-02-05 16 views
27

¿Por qué Scala no puede inferir el tipo de devolución del método cuando hay una declaración explícita return utilizada en el método?Tipo de inferencia en el método return type

Por ejemplo, ¿por qué se compila el siguiente código?

object Main { 
    def who = 5 
    def main(args: Array[String]) = println(who) 
} 

Pero el siguiente no.

object Main { 
    def who = return 5 
    def main(args: Array[String]) = println(who) 
} 

Respuesta

30

El tipo de devolución de un método es el tipo de la última instrucción en el bloque que lo define, o el tipo de expresión que lo define, en ausencia de un bloque.

Cuando usa return dentro de un método, introduce otra instrucción a partir de la cual puede regresar el método. Eso significa que Scala no puede determinar el tipo de ese return en el punto en que se encuentra. En su lugar, debe continuar hasta el final del método, luego combinar todos los puntos de salida para inferir sus tipos, y luego volver a cada uno de estos puntos de salida y asignar sus tipos.

Hacerlo aumentaría la complejidad del compilador y lo ralentizaría, por la única ganancia de no tener que especificar el tipo de devolución cuando se usa return. En el presente sistema, por otra parte, deducir el tipo de devolución viene de forma gratuita de la inferencia de tipo limitada que Scala ya utiliza.

Por lo tanto, al final, en el equilibrio entre la complejidad del compilador y las ganancias que se obtendrían, esta última se consideró que no valía la primera.

+5

Hola Daniel. No entiendo tu explicación Scala ya tiene que combinar múltiples expresiones y puntos de salida en funciones debido a las sentencias if/else. Y el lenguaje Scala tiene toneladas de cosas perversamente complejas que la mayoría de los programadores de Scala no entienden muy bien o usan (por ejemplo, covarianza/contravarianza, tipos estructurales, etc.). Esto agrega MUCHA complejidad al compilador; entonces "hace que el compilador sea más complejo" parece una respuesta débil. –

+4

@UrbanVagabond Te perdiste la parte "gana para ser cabeza". El hecho de que algo sea complejo no significa que valga la pena agregarle más complejidad. Ahora, Scala no tiene que combinar múltiples expresiones y puntos de salida en sentencias if/else porque if/else es una expresión, no enunciados. Eso puede parecer cortar el pelo, pero la diferencia es muy real. –

-2

No estoy seguro de por qué. Quizás solo para desalentar el uso de la declaración return. :)

1

Dada esta (2.8.Beta1):

object Main { 
    def who = return 5 
    def main(args: Array[String]) = println(who) 
} 
<console>:5: error: method who has return statement; needs result type 
     def who = return 5 

... parece no inadvertida.

11

Aumentaría la complejidad del compilador (y del lenguaje). Es realmente divertido hacer inferencias tipo sobre algo así. Como con cualquier tipo de inferencia relacionada, todo funciona mejor cuando tienes una sola expresión. Las declaraciones de rendimiento dispersas crean efectivamente una gran cantidad de ramificaciones implícitas que se vuelven muy adhesivas para unificar. No es que sea particularmente difícil, simplemente pegajoso. Por ejemplo:

def foo(xs: List[Int]) = xs map { i => return i; i } 

Qué, te pido, no inferir el compilador aquí? Si el compilador hiciera inferencia con declaraciones de devolución explícitas, necesitaría ser Any. De hecho, muchos métodos con declaraciones explícitas de devolución terminarían devolviendo Any, incluso si no se vuelve furtivo con devoluciones no locales. Como dije, pegajoso.

Y además de eso, esta no es una función de idioma que deba ser alentada. Los retornos explícitos hacen no mejoran la claridad del código a menos que haya solo un retorno explícito y que al final de la función. La razón es bastante fácil de ver si ve las rutas del código como un gráfico dirigido. Como dije antes, los retornos dispersos producen una gran cantidad de ramificaciones implícitas que producen hojas extrañas en su gráfica, así como muchas rutas adicionales en el cuerpo principal. Es simplemente funky. El flujo de control es mucho más fácil de ver si sus ramas son todas explícitas (coincidencia de patrones o expresiones if) y su código será mucho más funcional si no se basa en declaraciones de efectos secundarios return para producir valores.

Por lo tanto, al igual que varias otras características "desanimados" en Scala (por ejemplo, en lugar de asInstanceOfas), los diseñadores de la lengua hizo una elección deliberada para hacer las cosas menos agradable. Esto combinado con la complejidad que introduce en la inferencia de tipos y la inutilidad práctica de los resultados en todos los escenarios menos en los más elaborados. Simplemente no tiene sentido que Scalac intente este tipo de inferencia.

Moraleja de la historia: ¡aprende a no dispersar tus ganancias! Es un buen consejo en cualquier idioma, no solo en Scala.

+0

@ Daniel ... características "desalentadas" en Scala (p. Ej., ComoInstanceOf rather than as) ".... ¿Me perdí algo? No recuerdo' como' como una función en Scala (pero soy bastante nuevo en Scala , así que puede ser mi error.) – Jus12

+0

@ Daniel, creo que una recomendación aún mejor sería evitar el uso de 'return's (related: http://stackoverflow.com/questions/3770989/purpose-of-return-statement -in-scala) – Jus12

+1

No hay función 'as' en Scala. Hay un operador' as' en C# aunque funciona como el método 'asInstanceOf' en Scala. Mucha gente nueva en el lenguaje pregunta por qué el mecanismo de conversión de Scala es * tan * detallado, y la respuesta es simplemente para desalentar su uso. –

Cuestiones relacionadas