質問: [以下、追記] 質問の仕方が悪かったようなので、少し補足させていただきたいと思います。 thisコンストラクタにおいて、一行目で自身のコンストラクタを呼び出さなければならない言語仕様(制約)は知っています。 私が知りたいのは、何故、そのような制約があるのか、ということです。 何の理由もなくそのような制約が出来たとは考えづらいので、何らかの理由があるのだとは思いますが、その理由が私には皆目見当も付きません。 理由をごそんじの方、ご教授よろしくお願いいたします。
回答: 2番目のコードがエラーになる原因は、補助コンストラクターで最初(1行目)にクラス自身のコンストラクター、または他の補助コンストラクターを呼び出して、クラスのインスタンスを生成しなければならない言語仕様によるものではないでしょうか。 > > A constructor expression is either a self constructor invocation this(args1args1)......(argsnargsn) or a block which begins with a self constructor invocation. The self constructor invocation must construct a generic instance of the class. > > > 最初のコードは補助コンストラクタの最初に自身のコンストラクターを呼び出しているのでエラーになりません。 ``` class foo(val x: Int, val y: Int) { def this(x: Int) = { this(x, x + 1) } } ``` 余談ですが、`this()`を補助コンストラクター内で最初に呼び出さないとエラーになるのは、Javaでも同様のことかと思います。 ``` class foo { private final int x; private final int y; public foo(int x, int y) { this.x = x; this.y = y; } public foo(int x) { final int y = x + 1; this(x, y); // エラー } } ``` ScalaでもJavaでも`this()`の前にはありとあらゆる一切のコードが書けないと決められています。 (そのコードの問題の有無にかかわらず) 何故そのような言語仕様があるのかという質問に対し、様々な回答が考えられるかもしれませんが、1つの答えとしては、その方がすべての人にとってシンプルだからです。 以下、Scala、Javaに限らない可能な限り一般的な話を書きます。 > > この場合、thisコンストラクタ内の変数yは、hoo classのインスタンスのメンバであるyではなく、thisコンストラクタ内でローカルな変数なはずです。ローカルな変数はスタック上に配置されるはずだから、hooのインスタンスが生成されるより前にアクセスしても、問題はない気がするのですが。 > > > 「今回のコードでは問題ない」とのことですが、ではそのコードが問題ないことを確認するのは誰でしょうか? コンパイラです。 補助コンストラクタ内で`this()`が最初に呼び出されないことを許容すると、`this()`の前にありとあらゆるコードが書けます。 * 存在しないインスタンスのメンバやメソッドへのアクセス * abstractメソッドの呼び出し + これをoverrideしたメソッド内で何が行われるのかも分かりません + インスタンスが存在しないので、メンバやメソッドにもアクセスできません (このメソッド自体が呼び出せないと思いますが...) etc. ... これらのコードは`this()`の後に書かれていれば一切問題となりません。 では、これらの問題あるコードを含めた記述を可能にして、コンパイラがこの世のありとあらゆるコード(質問のような問題のないコードも含めて)を検査し、コンストラクタ内で問題があるコードをコンパイルエラーにすべきでしょうか? (コンパイルエラーとして検出できなかった場合、実行時エラーになるでしょう) IDEもこれらの問題のあるコードをリアルタイムにチェックすべきでしょうか? どのようなコードが問題、または問題ないのかを言語仕様にすべて明記し、言語使用者はそれをすべて把握(記憶)すべきでしょうか? コンパイルエラーが出た際にはその行数を見て、言語使用者が修正すべきでしょうか? 言語設計者、コンパイラ作成者、言語使用者から見て、「補助コンストラクタでは`this()`より前に一切のコードが書けない」と覚えるだけのことに比べて、これらは良いことでしょうか? 答えはもちろんノーです。 そのような言語は誰も使いたくありません。(もちろん私も) 言語仕様は可能な限りシンプル、かつ実用的であるべきです。 また、これは「ある問題を解決するために別の問題を持ち込むべきではない」という設計原則にも関係していて、実現したいことに対して多くの問題を持ち込み過ぎています。 これが「すべての人にとってシンプルな言語仕様を保つため」という観点での回答となります。 「何故そのようなものがあるのか」という疑問がわいたとき、「なかったらどうなるのだろうか」という観点で考えてみるのも良いかもしれません。