連載:C# 2.0入門

第4回 Findメソッドとnull許容型

株式会社ピーデー 川俣 晶
2007/08/31

MATステートメントの思い出

 1978年に発売された恐らく日本で最初のパーソナル・コンピュータとなるNEC PC-8001には、N-BASICというBASIC言語が搭載されていた。これは本体に組み込まれたROMに焼き込まれたもので、当然、入れ替えるためにはROM交換を必要とした(実際に、バージョン1.0から1.1へのバージョン・アップはROM販売という形で行われた)。

 さて、ROMという以上は書き換えができない。ならば一切の拡張性が拒絶されていたのかというと、そうではない。書き換え可能なRAM領域にジャンプしてから戻ってくるというコードが多く組み込まれていたのだ。これをフック(hook)という。RAM領域を書き換えてやれば、BASICのさまざまな処理を乗っ取って拡張することができた。

 また、拡張用の予約語として、特定の機能が割り当てられていないキーワードもいくつか用意されていた。例えば「talk」のような名前のステートメントが予約語として用意されていた。これを見て「音声合成機能がオプションとして提供されるはずだ!」と勘違いした人も多いようだったが、恐らくこれは当時有力であった外部拡張バスのGP-IB(IEE 488)の制御用に用意されたキーワードだったのだろう。GP-IBでは通信用語としてtalk/listenというような言葉を使うためである。

 さて、ほかの予約語として「MAT」というものがあった。これは、私がPC-8001を改造してカセット・インターフェイスを倍速化した際、それを活用するユーティリティ機能を起動するためのステートメントとして利用した。市販の倍速化回路は基板を追加してスイッチ切り替えで実現していたが、私の設計した回路はジャンパ線を6本追加するだけで、後はソフトの支援で切り替えを行う仕掛けになっていた。

 この自作MATコマンドは、「Monitor for Aki's Tape system」の略でMATだと称していたが、もちろん本当は違う。talkステートメントが音声合成ではなくGP-IB用だろう……と予測できるよりも確実に違う。これは間違いなく行列演算用に用意された予約語である。

 N-BASICには最後まで出現しなかったが、世の中にある一部のBASIC言語には行列演算を行うためのMATステートメントが存在するものがある。MATは行列(matrix)の略だろう。もちろん、実際には配列に対して作用する演算機能である。

 実例を軽く検索してみたところ、以下のような例が見つかった。

 サンプル・ソースも掲載されているので、興味のある人は見てみるとよいだろう。つまり、「MAT A=B+C」のようなステートメントは、配列の個々の値ではなく、配列全体に対して作用する演算機能として存在したわけである。

 少なくとも1978年の時点で、単独の値ではなく、値の集まりに対して作用する演算は(安価なパソコン・レベルでも)具体的な拡張の可能性として意識されていたわけである。

 単独の値ではなく、値の集まりに対して行われる演算機能は、明示的な繰り返し構文なしで複数の値に演算を行うことができる。それはソース・コードの量と質を大きく変えてしまう可能性を持つ。

 そして、世界の広さを少しでもまじめに意識する者は、1978年当時であっても、そのような可能性を実際に意識していたであろう。しかし、実際にはN-BASIC用の行列演算拡張は発売されることはなく、可能性はつかみどころのない幻のまま終わってしまった。

 ちなみに、このMATステートメントの話題は前振りの余談ではなく、実は本文の結論に対する重要な伏線である。

前回に語り残したこと:ForEachメソッドのbreak問題

 前回の「第3回 新しい繰り返しのスタイル」では、foreach文を使うよりも、System.Arrayクラスやジェネリック・コレクションのクラスなどが持つForEachメソッドを使う方が高速でお勧めだと書いた。

 しかし、これは単に置き換えればよいというものではない。実際には置き換えられない事例があるからだ。

 例えば、次のリスト1はそのままForEachメソッドに書き換えられない。

using System;

class Program
{
  static void Main(string[] args)
  {
    string[] 玉電駅名 = {
      "下高井戸","七軒町","六所神社前","山下","豪徳寺前","宮ノ坂"
    };

    foreach (string 駅名 in 玉電駅名)
    {
      if (駅名. Contains("前"))
      {
        Console.WriteLine(
            "前の付く駅名としては例えば{0}があります。", 駅名);
        break;
      }
    }
    // 出力:前の付く駅名としては例えば六所神社前があります。
  }
}
リスト1 ForEachメソッドに書き換えられない例

 試しに、リスト1をForEachメソッドを使うように書き換えてみたのがリスト2である。

using System;

class Program
{
  static void Main(string[] args)
  {
    string[] 玉電駅名 = {
      "下高井戸","七軒町","六所神社前","山下","豪徳寺前","宮ノ坂"
    };

    Array.ForEach(玉電駅名, delegate(string 駅名)
    {
      if (駅名. Contains("前"))
      {
        Console.WriteLine(
          "前の付く駅名としては例えば{0}があります。", 駅名);
        break;
      }
    });
  }
}
リスト2 実際にはコンパイルできない書き換え結果

 しかし、このソースは「break;」の行で以下のようなエラーになり、コンパイルできない。

エラー  1  break または continue に対応するループがありません。  D:\w\test\ConsoleApplication50\ConsoleApplication50\Program.cs  13  5  ConsoleApplication50
リスト2のコンパイル時に表示されるエラー

 コンパイルできない理由は明らかで、breakはループを脱出する文であるにもかかわらず、このソースにはループ(foreach/for/while/do)がないからである。

 実はForEachメソッドを使うと、break/continue/return文は機能しなくなってしまう。return文の機能はcontinue文相当になり、break/continue文は使用することができない。

 しかし、break文などでループを脱出するのは常識的に多用されるテクニックである。それが使えないとしたら、非常に問題が大きい。だが、foreach文抜きのプログラミングを行っていても、さほど困らない。

 それはなぜだろうか?


 INDEX
  C# 2.0入門
  第4回 Findメソッドとnull許容型
  1.MATステートメントの思い出/前回に語り残したこと:ForEachメソッドのbreak問題
    2.ForEachだけではない繰り返しメソッド/複数の結果が欲しい場合/偉大なる前進とは何か?/そしてC# 3.0とLINQへ続く
    3.null許容型とは何か?/なぜnullを入れたいのか
    4.null許容型の内部構造/null合体演算子
    5.is演算子の挙動に注意/3値論理型として使用できるbool?型/nullを許容するとパフォーマンスに影響するか?/補足:null許容への批判
 
インデックス・ページヘ  「C# 2.0入門」


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 記事ランキング

本日 月間