ローカル変数参照ルール

上に関連した話です。

ローカル変数参照の解決は、次のルールによって決定されます。

  • 外側のスコープに向かって、一番近い同名の変数を静的に探す。
  • 静的に見つからない場合、toplevelオブジェクトのメンバから動的に検索される。
  • toplevelに無い場合、例外が投げられる

以上です。つまり、thisを暗黙的な検索対象にはしません

C++Rubyでは、メソッドの中では、this (Rubyではself)を暗黙的に検索するため、少々戸惑うかもしれません。

  // C++
  class Foo{
  public:
    virtual void hoge();
    virtual void bar();
  };
  void Foo::hoge(){}
  void Foo::bar(){
    hoge();  // this->hoge();
  }
 // Xtal
 Foo : class{
   hoge : method(){}
   foo : method(){
     // ↓と書けるが、このhogeは静的にローカル変数として取得されている。
     hoge();  
   }
 }

これにより、Fooが継承されてhogeがオーバーライドされたとしても、相変わらずfooメソッドの中ではFoo::hogeが呼ばれつづけることになります。デザインパターンで言う「テンプレートメソッド」にならないわけです。
これをテンプレートメソッドとして動作させたいのならば、this.hoge(); と書きます。これで動的にhogeが検索されます。

何故このような挙動になっているのでしょうか?いくつか理由があります。

  • 実行速度が速くなる。
    • C++のように、静的な型付のコンパイルはされないため、thisを暗黙的に検索対象にしたら動的に検索するしかなくなる。それでは実行速度が落ちてしまうのは必然。
    • 「ローカル変数名」を使って検索する必要がなくなり、内部的に静的に振られた番号でアクセスできる。
  • 下底クラス実装者が予期していなかったメソッドのオーバーライドをされても大丈夫。
    • 上の例で、hogeはまったくオーバーライドされることを期待してなかったとします。サブクラス実装者が、hogeというメソッドをまったく違う用途として再定義してしまうと、やや複雑なバグが発生します。

Rubyも上と同じような、self.をつけた時だけオーバーライド呼び出しとする、という挙動にするかどうか論議があったようです。

他の言語に言及しているところでは自分は勘違いをしている可能性があります。もし間違いがありましたら指摘していただけると嬉しいです。