Вывод типа по типу возврата метода

Почему Scala не выводит возвращаемый тип метода, когда в методе используется явный оператор return?

Например, зачем компилируется следующий код?

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

Но это не так.

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

Ответы

Ответ 1

Возвращаемым типом метода является либо тип последнего оператора в блоке, который его определяет, либо тип выражения, определяющего его, в отсутствие блока.

Когда вы используете return внутри метода, вы вводите другое утверждение, из которого метод может вернуться. Это означает, что Scala не может определить тип этого return в найденной точке. Вместо этого он должен действовать до конца метода, а затем объединить все точки выхода для вывода их типов, а затем вернуться к каждой из этих точек выхода и назначить их типы.

Чтобы сделать это, это увеличит сложность компилятора и замедлит его, для единственного усиления отсутствия необходимости указывать тип возвращаемого значения при использовании return. В настоящей системе, с другой стороны, вывод возвращаемого типа происходит бесплатно от вывода ограниченного типа Scala уже использует.

Итак, в итоге, в балансе между сложностью компилятора и коэффициентами прибыли, последний считался неценным первым.

Ответ 2

Это увеличит сложность компилятора (и языка). Это просто на самом деле фанк, чтобы делать вывод типа на что-то подобное. Как и в случае с любым типом вывода, все работает лучше, когда у вас есть одно выражение. Рассеянные операторы return эффективно создают много неявного ветвления, которое становится очень липким для унификации. Это не то, что это особенно сложно, просто липкое. Например:

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

Что, я прошу вас, делает ли компилятор здесь? Если компилятор делал вывод с явными операторами return, это должно быть Any. Фактически, многие методы с явными операторами return вернут Any, даже если вы не получите подлый результат с нелокальными возвращениями. Как я сказал, липкий.

И кроме того, это не язык, который следует поощрять. Явные возвращения не улучшают ясность кода, если только один явный возврат и что в конце функции. Причина довольно проста в том, что вы просматриваете пути кода как ориентированный граф. Как я сказал ранее, разбросанные возвраты производят много неявного разветвления, которое производит странные листья на вашем графике, а также множество дополнительных путей в основном теле. Это просто фанки. Поток управления намного проще увидеть, являются ли ваши ветки явными (соответствие шаблону или выражения if), и ваш код будет намного более функциональным, если вы не будете полагаться на побочные эффекты return для создания значений.

Итак, как и некоторые другие "обескураженные" функции в Scala (например, asInstanceOf, а не as), разработчики языка сделали преднамеренный выбор, чтобы сделать вещи менее приятными. Это в сочетании со сложностью, которую она вводит в вывод типа и практическую бесполезность результатов во всех, кроме самых надуманных сценариев. Для скаляра просто не имеет смысла пытаться сделать такой вывод.

Мораль истории: научись не разбрасывать свои возвращения! Это хороший совет на любом языке, а не только Scala.

Ответ 3

Учитывая это (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

... кажется, это не случайно.

Ответ 4

Я не уверен, почему. Возможно, просто препятствовать использованию инструкции return.:)