連載

One Point .NET

クロス言語開発は本当にできるのか?

吉松 史彰
2002/06/20


 .NET Frameworkの中核をなすCommon Language Runtime(CLR)の特徴の1つとして、クロス言語開発が声高に喧伝されていた時期があった。そこでは、「好きな言語で開発して、それぞれを持ち寄って1つのアプリケーションにする」ということができるとされていた。実際に、VB.NET(Visual Basic.NET)でスローした例外をC#でキャッチしたり、C++で作ったクラスから継承したクラスをC#で作るデモなどが盛んに行われた。Java言語にしばられるデベロッパに対するマーケティング戦略という意味も多分にあったのだろう。

Misery

 先日、とあるWebサイトで面白い記事を見つけた。内容そのままではないが、こんなことを説明している。

public class Television {
  public void Show(string Message) {
    System.Console.WriteLine("Hmmm. As usual.");
  }
}

 これはC#で作ったテレビだ。C#は最先端の言語だから、当然こんなこともできる。

public class PlasmaDisplay : Television {
  public void Show(object Message) {
    System.Console.WriteLine("This is amazing!");
  }
}

 C#ならプラズマ・ディスプレイの作成もお手のものというわけだ。さて、当然ユーザーはプラズマ・ディスプレイで番組を見たいに決まっている。

class SharpUser {
  static void Main() {
    PlasmaDisplay pdp = new PlasmaDisplay();
    pdp.Show("Show me now!");
  }
}

 無事迫力の高精細画面を堪能できた。

 そこに、うわさを聞きつけたVB.NETユーザーがやってきた。彼女ももちろんプラズマ・ディスプレイで番組を見たいに決まっている。

Class BasicUser
  Shared Sub Main
    Dim pdp As New PlasmaDisplay()
    pdp.Show("Show me, show me!")
  End Sub
End Class

 彼女は怒って帰ってしまった。

 なかなか面白い現象だと思わないだろうか?

Guilty

 さて、この場合、悪いのはだれだったのだろうか? .NET Framework SDKのドキュメントの、「言語間の相互運用性」の項には、「Common Language Specification(CLS)を守っていれば、ほかの言語を利用するデベロッパがそのコードを完全に利用できる」と書かれている。PlasmaDisplayクラスは、きっとこのルールに違反しているに違いない!

 どこが違反しているのか手っ取り早く見つけるには、System.CLSCompliant属性を使うのが便利だろう。

[assembly:System.CLSCompliant(true)]
public class Television {
  public void Show(string Message) {
    System.Console.WriteLine("Hmmm. As usual.");
  }
}

public class PlasmaDisplay : Television {
  public void Show(object Message) {
    System.Console.WriteLine("This is amazing!");
  }
}

 再びコンパイルしてみる。もしもCLS違反のコードが見つかれば、コンパイル・エラーとなるはずだ。だが、このコードはコンパイルできてしまう。つまり、CLSに違反していないのである。本当かどうか疑問に思ったら、sbyteやuintなどのCLS違反となるデータ型を使うメソッドをpublicに宣言してみてほしい。コンパイル・エラーが確認できるだろう。

 CLSに違反していないのだから、C#のコードは悪くない。だとすれば、これはやはりお得意の「不具合」か? いやいや、これは「仕様」なのである。

Basic Instinct

 よくよく見ると、PlasmaDisplayクラスはShowメソッドを多重定義していることが分かる。片方はSystem.Stringを、片方はSystem.Objectを引数として取る。System.StringはSystem.Objectから派生していることも思い出しておこう。

 さて、C#コンパイラもVB.NETコンパイラも、以下のコードを見てメソッドの解決を試みる。

pdp.Show("Show me now!");

pdp.Show("Show me, show me!")

 結論をいうと、このときの両者のルールが異なるため、結果が異なるのである。

 大ざっぱにいうと、C#では末端クラスのメソッド定義に呼び出しと互換性のあるメソッドがあれば、それが使われる。この場合、PlasmaDisplayクラスのShowメソッドは、System.Objectを引数に取るので、文字列を渡そうとしている呼び出し元と互換性がある。そのため、PlasmaDisplayクラスのメソッドが呼ばれたわけだ。

 一方、VB.NETでは、継承関係をすべてたどって、多重定義されたメソッドを横一線に並べる。そして最も呼び出しに近いメソッドを選択する。この場合は、呼び出しが文字列を引数として渡しているので、TelevisionクラスのShowメソッドの方が、PlasmaDisplayクラスのShowメソッドよりも近い。だからこういう結果になるわけだ。

 実はCLSには、多重定義されたメソッドの解決法にかかわる規定が、あえて除かれている。そのため、各言語が独自にルールを定めているのだ。C#は新しい言語だし、VBにはオーバーローディングはなかったわけなので、VB.NETとC#で合わせてくれてもよかったのだが……。

 VB.NETとC#には、ほかにも異なる機能がある。次のページでご覧いただくインターフェイスもその1つだ。

 

 INDEX
  連載 One Point .NET
  クロス言語開発は本当にできるのか?
  1.Misery/Guilty/Basic Instinct
    2.Face/Off/What Lies Beneath/The Right Staff
 
「連載 One Point .NET」


Insider.NET フォーラム 新着記事
  • 第2回 簡潔なコーディングのために (2017/7/26)
     ラムダ式で記述できるメンバの増加、throw式、out変数、タプルなど、C# 7には以前よりもコードを簡潔に記述できるような機能が導入されている
  • 第1回 Visual Studio Codeデバッグの基礎知識 (2017/7/21)
     Node.jsプログラムをデバッグしながら、Visual Studio Codeに統合されているデバッグ機能の基本の「キ」をマスターしよう
  • 第1回 明瞭なコーディングのために (2017/7/19)
     C# 7で追加された新機能の中から、「数値リテラル構文の改善」と「ローカル関数」を紹介する。これらは分かりやすいコードを記述するのに使える
  • Presentation Translator (2017/7/18)
     Presentation TranslatorはPowerPoint用のアドイン。プレゼンテーション時の字幕の付加や、多言語での質疑応答、スライドの翻訳を行える
@ITメールマガジン 新着情報やスタッフのコラムがメールで届きます(無料)

注目のテーマ

Insider.NET 記事ランキング

本日 月間