...ing logging 4.0

はてなブログに移行しました。D言語の話とかいろいろ。

In A Module Far, Far Away Part 2 - Walter Bright

英語の勉強を目的として訳してみました.
まずタイトルが訳せないんですけどw
英和交互に書いているので読みにくいかもしれない.

In the last installment, we talked about how changing a declaration in one module can unexpectedly change the behavior of another module, and how language features can mitigate that. Here are some more features of the D programming language designed for that purpose.

前回,我々は1つのモジュールで宣言を変えることが,別のモジュールの挙動を予想外に変えてしまう方法と,言語機能がそれを軽減できる方法について話しました.この目的のために設計されるプログラミング言語Dにはさらなるいくつかの特徴があります.


Final Switch

Given an enum declaration:

まずenumを宣言します:

enum E { A, B, C }

and in the remote module there's a switch statement:

別のモジュールにはswitch文があります:

E e;
...
switch (e)
{   case A: ...
    case B: ...
    case C: ...
    default: assert(0);
}

The declaration for E gets updated to add a member D:

Eの宣言は,メンバーDを加えるために更新されました:

enum E { A, B, C, D }

and the switch statement, which is supposed to handle all the possibilities of E, is now incorrect. At least our intrepid programmer has anticipated this and put in a default that asserts. But this identifies the problem at runtime, if the test suites are thorough. We'd prefer to catch it at compile time in a guaranteed manner.

そして,Eのすべての可能性を取り扱うはずのswitch文は現在誤っています.少なくとも,我らが勇敢なプログラマーはこれを予想して defaultにassertを仕掛けました.しかし,テストスイートが完全である場合に限りこれは実行時に問題を検出します.我々は,コンパイル時に保証された方法でそれを捕えるのを好みます.

Enter the final switch statement:

final switch文を入力します:

final switch (e)
{  case A: ...
  case B: ...
  case C: ...
}

In a final switch statement, all enum members must be represented in the case statements. A default statement has no point, and is not even allowed in a final switch. If we add an unrepresented member D, the compiler dings us in the final switch.

final switch文では,case文ですべてのenumメンバーが現れなければなりません.final switchではdefault文は意味がないので存在することさえ許されません.現れていないメンバーDを我々が加えるならば,コンパイラはfinal switchにおいて警鐘を鳴らします.


Override

Given a class C declared in one module:

1つのモジュールの中でクラスCが宣言されました:

class C { }

and another module declares class D that derives from C, and declares a virtual method foo():

そして,別のモジュールはクラスCを継承するクラスDを宣言し,仮想関数foo()を宣言します:

class D : C { void foo(); }

Later, a method foo() is added to class C:

その後,関数foo()がクラスCに加えられます:

class C { void foo(); }

Now, the call to C.foo() gets inadvertently hijacked by D.foo(), which may be quite unrelated. The solution is to mark intentional overriding with the override keyword:

今,C.foo()の呼び出しは,全く無関係かもしれないD.foo()によって意図せず乗っ取られます.これの解決方法はoverrideキーワードでオーバーライドすることを意図的にマークすることです:

class B : A { override void bar(); }

Then, if a method overrides a base class method, but is not marked with override, the compiler issues an error.

それから,もしあるメソッドがベースクラスメソッドをオーバーライドするが,overrideでマークされないならば,コンパイラはエラーを出します.


Function Hijacking

関数ハイジャック

In module A, there's a function:

モジュールAにおいて,ある関数があります:

void foo(long x);

Module C imports A, and B and calls foo() with an int argument:

モジュールCがAとBをインポートしていて,intの引数と共にfoo()を呼び出します.

import A;
import B;
...
...
foo(3);

Now, the designer of B, having no knowledge of A or that C imports A and B, adds the following declaration to B:

今,Aの知識を持たない,あるいは,AとBをインポートするCの知識を持たないBの設計者が,以下の宣言をBに加えます:

void foo(int x);

Suddenly, C.foo(3) is calling B.foo(3) because B.foo(int) is a better match for 3 than A.foo(long). B.foo(int) is said to have hijacked the call to A.foo(long). In D, such overloading across modules would generate a compile time error if a call from C matches functions from more than one import. Overloading across imports must be done intentionally, not by default, by using an alias declaration:

引数が3のとき,B.foo(int)はA.foo(long)よりもマッチするので,突然,C.foo(3)はB.foo(3)を呼び出します.B.foo(int)はA.foo(long)に呼び出しを乗っ取られたといわれます.D言語では,もしCからの呼び出しが複数のインポートからの関数にマッチするならば,そのような複数のモジュールにまたがるオーバーロードは,コンパイル時エラーを引き起こすでしょう.複数のインポートにまたがるオーバーロードは,デフォルトのままではなくalias宣言を用いて故意に行われなければなりません:

import A;
import B;
alias A.foo foo;
alias B.foo foo;
...
foo(3);  // calls B.foo(int)

There's a lot more to function hijacking.

関数ハイジャックにはもっと多くのものがあります.


Conclusion

まとめ

It's a worthy goal of language design to be able to prevent changes in declarations in one module from producing unexpected bad behavior in another. While I know of no way to eliminate all such cases, D makes some major steps in closing common loopholes.

1つのモジュールでの宣言の変更が他のモジュールの中で予期しない悪い振る舞いを生じることを防げることは,言語設計の価値あるゴールです.私はすべてのそのようなケースを除く方法を知らないとはいえ,D言語は一般の隙間を埋めるいくらかの大きな一歩です.

If you want to learn more about how real compilers work, I am hosting a seminar in the fall on compiler construction.

もし本当のコンパイラが働く方法についてあなたがより学びたいならば,私はコンパイラ構築に関するセミナーを主催しています.

Thanks to Jason House and Don Clugston for their helpful comments on this.

この記事についてのJason HouseとDon Clugstonの役に立つコメントに対して感謝します.