...ing logging 4.0

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

Issue 5328 - The addressof-expression that should be rejected is accepted

本文では全然説明してないですが「"m"がインスタンスメソッドなのに"&A.m"と書けてしまっているけどこれバグじゃないの.クラス定義の中ではちゃんとエラーになるけど外ではエラーにならないで実行時にならないと問題が発覚しなくなっているよ」というつもりで報告したら,「それは仕様です」と返ってきたので考え直してみました.

// a.d
void f(void function() m) { m(); }

class A
{
    this()
    {
        f(&A.m); // rejects-invalid => OK
    }

    /+static+/ void m() {}
}

void main()
{
    f(&A.m); // accepts-invalid => BAD!!
}
$ dmd a.d
a.d(7): Error: function a.f (void function() m) is not callable using argument
types (void delegate())
a.d(7): Error: cannot implicitly convert expression (&this.A.m) of type void
delegate() to void function()

You will get the following result if you remove A.this constructor.

$ dmd a.d
object.Error: Access Violation

一部わからないところがあったり全体についてもあんまり自信はないけれど自分で読むために訳したので載せておきます.あえて話しているかのように訳してみました.

It's a feature, not a bug. You can take the address of methods without providing an object reference (i.e. no this pointer, or what would be the context member of method delegates).

それはバグじゃなくて仕様だよ.あなたはオブジェクトを作らなくてもメソッドのアドレスを取れるよ(つまりthisポインタや他の何らかのメソッドデリゲートのコンテキストメンバがなくても・・・?).

The returned function pointer is simply what the class' vtable contains. The function signature is the same as the signature of a proper delegate to the method. It doesn't make sense to call the function pointer by itself (wrong calling convention, this pointer is missing), but it's useful for other things.

返された関数ポインタは,単にクラスのvtableを含むものだ.その関数シグネチャは,メソッドへの適切なデリゲートのシグネチャと同じだよ.単独でその関数ポインタを呼ぶことは意味をなさない(呼び出しコンベンションが間違っているからポインタは不正だね),でもそれは他のことに役立つよ.

E.g. you can use the type of the function pointer value in meta programming to get the method's signature. That's very important for meta programming. You could just instantiate a new object, and then analyze the delegate, but why should you need to construct a dummy object? For the actual value of the function pointer there are also valid uses. Think about serialization of delegates, for example.

例えば,あなたはメソッドのシグネチャを得るために,メタプログラミングで関数ポインタの値の型を使うことができる.それはメタプログラミングにとって非常に重要だね.あなたは今新しいオブジェクトをインスタンス化してからデリゲートを取れるけど,どうしてダミーのオブジェクトを作る必要があるのだろう?そしてまた関数ポインタの実際の値のためには有効な用途がある.例えば,デリゲートのシリアライゼーションについて考えてみて欲しい.

Note that the delegate property .funcptr returns a similarly non-sensical function pointer. The context is missing and the calling convention is incompatible. If you call it, you get an access violation as well.

デリゲートプロパティ.funcptrが同様に無意味な関数ポインタを返すことに注意しよう.そのコンテキストはなくなっていて,そして,呼び出しコンベンションには互換性がない.あなたがそれを呼ぶなら,同じように一般保護違反が起こるよ.

What is happening here is that the language "designers" just didn't feel like introducing a dedicated separate function type for this purpose. Instead, they reused the "normal" function pointer type, even if calling it makes no sense. Basically it's a quick language hack that endangers type-safety and confuses users.

ここで起こっていることは,言語「設計者」が丁度この目的のために専用の別々の関数型を導入する気がなかったということだ.その代わりに,たとえそれを呼ぶことが意味をなさないとしても,彼らは「通常の」関数ポインタタイプを再利用した.基本的に,それは型安全性を危険にさらして,ユーザを混乱させるお手軽な言語ハックだ.

Btw. the code inside A.this is not accepted, because the "A." from "&A.m" just qualifies the member "m". Inside the ctor it's exactly the same as writing "&m". And &m is a delegate, not a function. So everything is alright. Though this slight syntactic ambiguity is another hint that D as a language is actually quite unorthogonal and full of special cases. Maybe "&typeof(this).m" in the ctor would do the same as the &A.m in main()?

ところで,A.thisの内側のコードは,「&A.m」の「A.」がまさにメンバ「m」を制限するから,受け入れられないんだ.それはまさにctorの中に「&m」を書くことと同じだね.そして,&mはデリゲートであって関数ではない.それですべては問題ないんだ.このわずかな統語的曖昧性がもう一つのヒントであるけれども,言語としてのD言語は実は全く直交していない特例でいっぱいだ.多分,ctorでの「&typeof(this).m」は,main()での&A.mと同じように動くんじゃないかな?

5328 – The addressof-expression that should be rejected is accepted

おっしゃるようにメタプログラミングのために関数シグネチャを得る方法は必要だけれど,それを呼び出せてしまってはよくないのでコンパイル時にエラーにすることはできないんでしょうか.

  • "m"がインスタンスメソッドのとき,そのデリゲートを得るには,クラス定義の内側では"&m"もしくは"&this.m"と書き,外側では"&obj.m"と書く.
  • "m"がクラスメソッドのとき,その関数ポインタを得るには,クラス定義の内外で"&A.m"と書く.

これではダメなんですかね.
そういうことを英語で説明できたらいいんですけど難しい・・・.


あと,デリゲートのシリアライゼーションについてはどんな議論ができるのか全然想像できないのでこれについてはコメントできません.