QA@IT

Scalaでメソッドのオーバーロードがコンパイル時にエラーになる理由を教えてください

441 PV

メソッド内で引数違いの同名のメソッドを呼び出した際に以下のようなコードではコンパイルエラーとなり、
overloaded method a needs result typeと出力されてしまいます。

object Main extends App {
    def a = 100
    def a(x: Int) = a * x //※1

    println(a + a(10))
}

しかし、※1のメソッドに戻り値の型を追加すると正常に動作します。

object Main extends App {
    def a = 100
    def a(x: Int): Int = a * x

    println(a + a(10))
}

型推論で戻り値の型は十分特定できるので前者でも大丈夫だと思っていたのですが、後者でないといけないのはなぜなのでしょうか?
また、IntelliJのエディタ上でも前者のコードで警告が出ることはありませんでした。
検証環境はScala 2.12.6を使用しています。

どなたかご存知の方おりましたらご教授ください。

回答

あまり深くみていないですが、このstackoverflowの回答と同じではないでしょうか

https://stackoverflow.com/a/3127260/2513010

だいぶ省略して引用します:

When Explicit Type Annotations Are Required.

  • When a method is overloaded and one of the methods calls another. The calling method needs a return type annotation.
def a(x: Int) = a * x //※1

は、 質問文にもありますが他のオーバーロード(引数なし a)を呼び出しているメソッドであるので、このケースに当てはまると思います。

編集 履歴 (2)
  • すいません、返信遅くなりました。
    結局はそういう仕様だから仕方ないということなんでしょうか。
    IntelliJでは正しく推測できている以上、必然性は感じないので、なぜそうなっているのかという理由が分かれば一番良いのですが。。。
    -
  • 具体的な例はあげられませんが、Scalaの推論の方式と静的型付け言語にコンパイルされなければならない部分などが関連していそうですね。もう少し具体的には、推論によってより抽象的な型に推論されることがあり(たとえばintを期待していたがミスや誤った代入によりAnyに推論された)、それによってコンパイルは通るが実行時エラーが起きてしまうため、 -
  • (公開APIでは特に)戻り値の型が明示される方が良いという方針があるようです(Scala自体をシンプルに保つためというのも含まれるプラクティス)。 -
ウォッチ

この質問への回答やコメントをメールでお知らせします。