C/C++ プログラマのための JavaScript 入門: スクリプト言語

no extension

前回「スクリプト言語」という言葉を何の定義もなく使ってしまいましたが, 考えてみると「スクリプト言語」の定義が何かというのは微妙です。

ネットにある解説の大抵は「簡易プログラミング言語」のようです。 しかしこれは「スクリプト言語」というよりはむしろアプリケーション上のユーザ操作を自動化する「マクロ言語」を指しているように思えます。 スクリプト言語の例としては(現在の) Perl や Ruby や Python といった言語が挙げられますが, これらは大規模アプリケーションにも使える本格的なプログラミング言語です。 JavaScript はウェブ・ブラウザとセットになっていることがほとんどなのでウェブ・ブラウザのマクロ言語と見なされがちですが, 実際には違います。 前回「WSH を使う」と決めたのも, そうしたイメージを払拭する狙いがありました。

一方, スクリプト言語を「動的型付け言語」と説明する解説もあるようです。 私はむしろこちらのほうがしっくりします。 そしてこれこそが C/C++ に慣れたプログラマにとって異質な部分なのだと思います。

C/C++ でプログラミングを行う場合, プログラマの頭の中では記述しているコードが最終的にどのようなインストラクション(マシン語命令)に「コンパイル」されるかイメージできています。 ある C/C++ コードが最終的にどのようなインストラクションになるかは, コードの内容とコンパイラの性能(およびコンフィギュレーション)とターゲット・プラットフォームによって決まります。 あるターゲットについてコンパイラが吐き出すアセンブラ・コードを一度も見たことがないとかいう C/C++ プログラマは適性に問題ありです(職業プログラマの話ですよ)。

私が昔書いた記事(PDF)からひとつ例を挙げましょう。 あるマイコン用の C ソースです。

int sum(int *tbl, int ct)
{
  register int sum;
  sum = 0;
  for(; ct>0; ct--, tbl++) {
    sum += (*tbl);
  }
  return(sum);
}

これはよくある SUM 値計算のロジックです(とりあえず桁あふれや境界違反については目をつぶってください)。 これを4でアンロールすると以下のようになります。

int sum(int *tbl, int ct)
{
  int sum, i;
  sum = 0;
  for(i=ct>>2; i>0; i--, tbl+=4) {
    sum += tbl[0];
    sum += tbl[1];
    sum += tbl[2];
    sum += tbl[3];
  }
  for(i=ct&3; i>0; i--, tbl++) {
    sum += (*tbl);
  }
  return(sum);
}

ロジックとしてはあまりにも冗長ですが, 実はターゲットとなるプロセッサによっては(ループ回数を減らせるため)この方が実行速度が速くなる場合があります。 (実際にはこの手法は古臭いものとなっています。あしからず)

C/C++ によるプログラミングの最終目的は最適なインストラクションを実装することです。 そのためには静的な型付けが必要になりますし, C コード上の簡潔さを犠牲にしてもインストラクションレベルで最適になるようにチューニングする必要もあります。 一方, スクリプト言語はまったく違う発想が要求されます。 上述の例のような「4でアンロール」といった小手先のテクニックはまったく意味がありません。 インストラクションを意識しないので, 静的な型付けを行う必要もありません。 スクリプト言語のコードで要求されるのは簡潔なロジック(ステップ数が少ないという意味ではないですよ,念のため)です。 つまり C/C++ のような言語とスクリプト言語では最適化(リファクタリング)の目的や観点が異なるということです。