hariport

haripo.com

なぜ HSP では関数を使わないのか

HSP、ご存知ですか。

HSPTV!

Hot Soup Processor と呼ばれるゲーム制作に特化したプログラミング言語です。 なんと開発セットに公式エディタまで付属しており、簡易にゲームを作ることができます。 小学生向けの入門書が売ってるレベル。 私も小学生のころに HSP に触れてプログラミングの世界に入門しました。

さて、かねてより HSP にまつわる疑問として 「なぜ HSP では関数を使わないのか」というのがありました。 HSP では基本的にサブルーチンを使います。

gosub *sub // call subroutine

*sub
   // something
   return

こんな感じです。 gosub 命令によって指定されたラベル *sub に処理がジャンプし、 return命令によってサブルーチンから呼び出し元にジャンプする。 ここには引数も変数スコープもありません。基本的に HSP の変数はすべてグローバルです。

一方で関数はないのかというと、もちろん HSP において関数を定義することが可能で、 これはローカルスコープもあり引数も取れます。 なぜ関数を使わないのか。 小学生当時は疑問に思いませんでしたが、関数の様々なメリットを理解して以降、 なぜそのプログラミングスタイルが推奨されているのか、意味が分かりませんでした。

しかし最近になってようやく気づいたのですが、 この疑問の答えはおそらく、「関数は難しい」からなのだと思います。

関数はなぜ難しいか。 まず、関数はいくつかの機能の複合だからです。

  1. 処理順を変える
  2. スコープを作る
  3. 引数をコピーする
  4. 戻り値を返す

関数を理解するためには、「スコープとはなにか」、 「引数とはなにか」を理解せなばなりません。 これらを天下り的に教えたとして、 「なぜグローバル変数で受け渡さないのか」、 「スコープを作るメリットはなにか」を曖昧なままに コーディングを進めると、結局は関数のメリットが生きない、 サブルーチンと同じような関数を書いてしまうでしょう。 コーディング経験の浅い小学生にこれを理解させるのは難しいと思います。

もうひとつ、関数が難しいのは、同じ関数が宣言、呼び出し、定義の 3 通りの記法で現れる点です。

// 宣言
int func(int);

int main() {
  // 呼び出し
  a = func(3);
} 

// 定義
int func(int v) {
  return v;
}

これは C 言語っぽい記法ですが、それぞれで必要なものが異なっています。 宣言には戻り値の型と引数の型が必要ですが、呼び出しには不要です。 定義には引数名が必要ですが、宣言と呼び出しには不要です。 そして宣言と定義には左辺値は書けません......。

理解してしまえば簡単ですが、人によってはこのあたりは混乱します。 本当に混乱するんですよ。a = func(int 3); とか書いたり......。

さて、ここで HSP のサブルーチンを思い出しましょう。

gosub *sub

*sub
   // something
   return

サブルーチンは「処理順を変える」以外の機能を持たず、 さらに引数も戻り値もないため記法も簡易です。 プログラミング初心者に対象を絞ったがゆえの潔さがあります。 迷いようがありません。最高。

というわけで、最近気づいた「なぜ HSP では関数を使わないか」でした。 HSP すごい、よく練られた言語だったんだな。