24997


scalaのthis補助コンストラクタに関してご教授ください。  
scalaのthis補助コンストラクタは、関数の先頭でそれより前に定義された別のコンストラクタを呼び出す必要があります。  
例えば次のhoo関数がそうです。

[code]

    class hoo(val x: Int, val y: Int){
        def this(x: Int){
        this(x, x+1) /* ここで前のコンストラクタを呼び出す*/
        }
     }
    
[/code]

ここであえて、hoo関数と意味上は等価なbar関数を作りたいと思います。

[code]

    class bar(val x: Int, val y:Int){
        def this(x: Int){
        val y = x + 1 /*コンパイルエラー*/
        this(x, y)
        }
     }
    
[/code]

valが再代入が不可能な以上、hoo関数とbar関数は同じものに思えます。  
しかしながら、hoo関数はコンパイルが通り、bar関数はコンパイルが通りません。  
理由は仕様のためと判っていますが、同じ意味を持つ二つの関数が、表記の違いだけで、片方はコンパイルが通り、もう片方はコンパイルエラーになるというのは、私には不思議に思われます。  
何故、Scalaではこのような仕様になっているのでしょうか？

よろしくお願いいたします。

===========================================================================

[以下、追記]

質問の仕方が悪かったようなので、少し補足させていただきたいと思います。  
thisコンストラクタにおいて、一行目で自身のコンストラクタを呼び出さなければならない言語仕様（制約）は知っています。  
私が知りたいのは、何故、そのような制約があるのか、ということです。  
何の理由もなくそのような制約が出来たとは考えづらいので、何らかの理由があるのだとは思いますが、その理由が私には皆目見当も付きません。  
理由をごそんじの方、ご教授よろしくお願いいたします。


CC BY-SA 3.0
2016-05-19T12:24:30.510
24996
2016-05-19T17:55:39.620
2016-05-19T14:07:07.413
5970
5970
question
scala
scalaのthis補助コンストラクタに関して


2番目のコードがエラーになる原因は、補助コンストラクターで最初(1行目)にクラス自身のコンストラクター、または他の補助コンストラクターを呼び出して、クラスのインスタンスを生成しなければならない言語仕様によるものではないでしょうか。

<http://www.scala-lang.org/files/archive/spec/2.11/05-classes-and-
objects.html#constructor-definitions>

> 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.

最初のコードは補助コンストラクタの最初に自身のコンストラクターを呼び出しているのでエラーになりません。

[code]

    class foo(val x: Int, val y: Int) {
      def this(x: Int) = {
        this(x, x + 1)
      }
    }
    
[/code]

余談ですが、`this()`を補助コンストラクター内で最初に呼び出さないとエラーになるのは、Javaでも同様のことかと思います。

[code]

    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); // エラー
        }
    }
    
[/code]

ScalaでもJavaでも`this()`の前にはありとあらゆる一切のコードが書けないと決められています。  
(そのコードの問題の有無にかかわらず)

何故そのような言語仕様があるのかという質問に対し、様々な回答が考えられるかもしれませんが、1つの答えとしては、その方がすべての人にとってシンプルだからです。

以下、Scala、Javaに限らない可能な限り一般的な話を書きます。

> この場合、thisコンストラクタ内の変数yは、hoo
> classのインスタンスのメンバであるyではなく、thisコンストラクタ内でローカルな変数なはずです。ローカルな変数はスタック上に配置されるはずだから、hooの‌​インスタンスが生成されるより前にアクセスしても、問題はない気がするのですが。

「今回のコードでは問題ない」とのことですが、ではそのコードが問題ないことを確認するのは誰でしょうか？  
コンパイラです。

補助コンストラクタ内で`this()`が最初に呼び出されないことを許容すると、`this()`の前にありとあらゆるコードが書けます。

  * 存在しないインスタンスのメンバやメソッドへのアクセス
  * abstractメソッドの呼び出し 
    * これをoverrideしたメソッド内で何が行われるのかも分かりません
    * インスタンスが存在しないので、メンバやメソッドにもアクセスできません  
(このメソッド自体が呼び出せないと思いますが…)

etc. ...

これらのコードは`this()`の後に書かれていれば一切問題となりません。

では、これらの問題あるコードを含めた記述を可能にして、コンパイラがこの世のありとあらゆるコード(質問のような問題のないコードも含めて)を検査し、コンストラクタ内で問題があるコードをコンパイルエラーにすべきでしょうか？  
(コンパイルエラーとして検出できなかった場合、実行時エラーになるでしょう)

IDEもこれらの問題のあるコードをリアルタイムにチェックすべきでしょうか？

どのようなコードが問題、または問題ないのかを言語仕様にすべて明記し、言語使用者はそれをすべて把握(記憶)すべきでしょうか？

コンパイルエラーが出た際にはその行数を見て、言語使用者が修正すべきでしょうか？

言語設計者、コンパイラ作成者、言語使用者から見て、「補助コンストラクタでは`this()`より前に一切のコードが書けない」と覚えるだけのことに比べて、これらは良いことでしょうか？

答えはもちろんノーです。  
そのような言語は誰も使いたくありません。(もちろん私も)  
言語仕様は可能な限りシンプル、かつ実用的であるべきです。

また、これは「ある問題を解決するために別の問題を持ち込むべきではない」という設計原則にも関係していて、実現したいことに対して多くの問題を持ち込み過ぎています。

これが「すべての人にとってシンプルな言語仕様を保つため」という観点での回答となります。

「何故そのようなものがあるのか」という疑問がわいたとき、「なかったらどうなるのだろうか」という観点で考えてみるのも良いかもしれません。


CC BY-SA 3.0
2016-05-19T13:28:52.163
24997
2016-05-19T17:55:39.620
2016-05-19T17:55:39.620
3068
3068
24996
answer