今回は、ただのお遊びである。
役に立たないばかりか、下手に参考にすると有害である。
VBAにはGoTo命令がある。On Error GoToのことではなく、普通のGoToだ。
決して「活用しよう」などと思ってはいけないが、遊びでコードを作る分には頭の体操になって良いかもしれれない。
GoTo命令を使うと、任意のラベルにジャンプできる。
ラベルは文字列にコロンをつけたものだ。
これを使えばループ命令を使わずにプログラムが書ける。。。というより、コンピューター内部ではループ命令はジャンプに置き換えられているので、GoToを使った方法はよりマシン語に近い書き方ということになるかもしれない。
また、ラベルを使えば、条件分岐はIfブロックではなく単行のIfで事足りる。
※これもマシン語に近い書き方であるが、マシン語の方は比較結果を一度フラグレジスタに入れてからジャンプする。
さて、GoTo使ってFizzBuzzを書いてみた。
Sub GoToFizzBuzz() i = 0 L: i = i + 1 If i > 100 Then GoTo L4 If i Mod 15 = 0 Then GoTo L1 If i Mod 3 = 0 Then GoTo L2 If i Mod 5 = 0 Then GoTo L3 Debug.Print i GoTo L L2: Debug.Print "Fizz" GoTo L L3: Debug.Print "Buzz" GoTo L L1: Debug.Print "FizzBuzz" GoTo L L4: End Sub
これをフローチャートへ落とし込むと、以下のようになる。
(フローチャートは久しく描いていないので厳密に合ってるかどうかは不明)
これはまだラベルLに収束するから分かりやすい方だが、GoTo命令はどこへでも好きなラベルにジャンプできるので、その性質をフル活用してしまうと、フローもあさっての方向へ飛んでいってしまう。
ある程度大きなプログラムで広範囲にわたってGoToが使われた場合、もはや作った本人ですら読めなくなることが多い。
そしてソースコードは絡みに絡み、おいしいスパゲッティの出来上がりというわけだ。
これが、GoToを使うなといわれる所以である。
次にGoSubという命令を紹介する。
この命令はラベルに飛ぶところまではGoToと同じだが、Returnという命令で呼び出し元に戻ってくる。
いわば、原始的なプロシージャのようなものである。
今度はこれを使ってFizzBuzzを書いてみた。
一部ループと終了処理にGoToを使用しているが、分岐はGoSubのみで実装した。
Sub GoSubFizzBuzz() i = 0 MainLoop: GoSub Judge If i < 100 Then GoTo MainLoop GoTo Fin Judge: i = i + 1 flg = False If i Mod 15 = 0 Then GoSub FizzBuzz If Not flg And i Mod 3 = 0 Then GoSub Fizz If Not flg And i Mod 5 = 0 Then GoSub Buzz If Not flg Then Debug.Print i Return Fizz: Debug.Print "Fizz" flg = True Return Buzz: Debug.Print "Buzz" flg = True Return FizzBuzz: Debug.Print "FizzBuzz" flg = True Return Fin: End Sub
※面倒なのでフローは割愛。
さて、コードは長くなったが、GoSubは必ず元の場所に戻ってくると分かっており、あさっての方向にジャンプする心配が無い。
(飛んだ先でさらにGoTo島流しなんてのは無いという前提)
プログラミングの黎明期には、GoSubの登場は画期的だったことだろう。
今ではプロシージャの分割やIfブロック、Loop命令、For命令などがあるのでこれらの命令を使うことは無い。
でもたまには、便利に使っている「あの機能」が無かったらどうなるんだろうと考えるのも楽しい。
皆さんも一度、チャレンジしてみてはどうだろうか。
きっと普段当たり前に使っている機能の、本当の価値が分かると思う。
ただし、大事なことなので二度書くが、決して「活用しよう」などと思ってはいけない。
※GoTo擁護派というのもあるらしく、そのあたりを学ばれた方がメリット・デメリットを踏まえて使うのはアリかもしれません。ただ、少なくともプログラミングの腕によほどの自信がなければ、実務コードでは使うべきではないと思います。
以上