¿Por qué Scala requiere que las funciones tengan un tipo de retorno explícito?

11

Recientemente comencé a aprender a programar en Scala, y hasta ahora ha sido divertido. Realmente me gusta la capacidad de declarar funciones dentro de otra función que parece algo intuitivo.

Un motivo favorito que tengo sobre Scala es el hecho de que Scala requiere un tipo de retorno explícito en sus funciones . Y siento que esto obstaculiza la expresividad del lenguaje. También es difícil programar con ese requisito. Tal vez sea porque vengo de la zona de confort de Javascript y Ruby. Pero para un lenguaje como Scala que tendrá toneladas de funciones conectadas en una aplicación, no puedo concebir cómo hago una lluvia de ideas en mi cabeza exactamente qué tipo de función particular que estoy escribiendo debería regresar con recurrencias después de las recurrencias.

Este requisito de declaración explícita de tipo de retorno en funciones, no me molesta para lenguajes como Java y C ++. Las recursiones en Java y C ++, cuando ocurrieron, a menudo se trataron con 2 a 3 funciones como máximo. Nunca varias funciones encadenadas juntas como Scala.

Entonces, me pregunto si hay una buena razón por la cual Scala debería tener el requisito de que las funciones tengan un tipo de retorno explícito.

recolección de basura
fuente
55
No lo hace, y no veo por qué sería un problema si lo hiciera.
Keith Thompson el
1
Pensé que sí. ¿Hay casos en Scala donde el tipo de retorno para una función es realmente ambiguo?
recolección de basura

Respuestas:

15

Scala no requiere un tipo de retorno explícito en todas las funciones, solo recursivas. La razón de esto es que el algoritmo de inferencia de tipo de Scala es (algo parecido a) un escaneo simple de principio a fin que es incapaz de mirar hacia adelante.

Esto significa que una función como esta:

def fortuneCookieJoke(message: String) = message + " in bed."

no necesita un tipo de retorno, ya que el compilador de Scala puede ver claramente, sin usar variables lógicas o mirar cualquier cosa que no sean los parámetros del método, que el tipo de retorno debe ser String.

Por otro lado, una función como esta:

def mapInts(f: (Int) => Int, l: List[Int]) = l match {
  case Nil => Nil
  case x :: xs => f(x) :: mapInts(f, xs)
}

provocará un error en tiempo de compilación, porque el compilador Scala no puede ver, sin usar variables anticipadas o lógicas, exactamente cuál es el tipo de mapInts. Lo máximo que podría decir, si fuera lo suficientemente inteligente, es que el tipo de retorno es un supertipo de List[Nothing], ya que Niles de ese tipo. Eso no le proporciona información suficiente para determinar con precisión el tipo de retorno de mapInts.

Tenga en cuenta que esto es específico de Scala y que hay otros lenguajes tipados estáticamente (la mayoría de la familia Miranda / Haskell / Clean, la mayoría de la familia ML y algunos otros dispersos) que utilizan algoritmos de inferencia de tipos mucho más completos y capaces que Scala usa. Además, tenga en cuenta que esto no es completamente culpa de Scala; el subtipo nominal y la inferencia de tipo de módulo completo están fundamentalmente en desacuerdo entre sí, y los diseñadores de Scala optaron por favorecer el primero sobre el segundo en aras de la compatibilidad con Java, mientras que los lenguajes funcionales estáticos "más puros" se diseñaron principalmente con el Opción opuesta en mente.

Llama de Ptharien
fuente
44
En realidad, el problema no es tanto descubrir un algoritmo de inferencia de tipo más completo. Está descubriendo un algoritmo de inferencia de tipos más completo, al tiempo que mantiene la alta calidad de los mensajes de error en el compilador Scala actual.
Jörg W Mittag
1
¿No sería el retorno correcto para case Nilrealmente un vacío List[Int]()? En cuyo caso, un compilador suficientemente inteligente podría resolverlo. Sin embargo, eso es todo jugando a Devil's Advocate, supongo.
KChaloux