2013/05/02(木) [n年前の日記]
#4 [prog] gotoについて思うところをつらつらと
HSPを勉強してるうちに、「gotoって…どうなんだろうなあ…」と思えてきたので、そのあたりをなんとなくメモ。ま、何十年も前に、gotoの是非については熱い議論があったらしいので、お前いまさら何言ってんだって感じの話ですが。
以下は自分の勝手な想像その他諸々なので事実とは大きく異なる可能性が高いです。
どんな高級言語で書かれたソースも、コンピュータ上で動くときにはバイナリになる・機械語レベルになるわけで。そして機械語レベルでは、ジャンプ命令 ≒ goto だらけになるわけですよ。そのことを考えれば、「gotoさえ知っていれば全てのプログラムは書けるんだ」という考えは正しいよなと。実際、全てのプログラムは、最終的にはそういう形で動いているのだし。
でも、それぞれの goto には、目的があって。
そこで先輩達は思いついた。「この goto はこういう目的で使っているんだよ、とソースにあらかじめ書いておくことにしようぜ」と。
ところが、今度は色んな命令を覚えないといけなくなった。今までは、goto だけ覚えておけばどうとでもなったのに…。
そこで誰かが言い出すのです。「プログラミング初心者に、こんなにたくさん命令を覚えさせるのはよくない。絶対混乱するよ…。だから、goto だけ教えとこう!」
ということで。このあたり2つの主張が成立しそうだなと。
後者の考え方がないと、高級言語なんてものは、生まれてこなかったであろう気もしてきたり。
以下は自分の勝手な想像その他諸々なので事実とは大きく異なる可能性が高いです。
どんな高級言語で書かれたソースも、コンピュータ上で動くときにはバイナリになる・機械語レベルになるわけで。そして機械語レベルでは、ジャンプ命令 ≒ goto だらけになるわけですよ。そのことを考えれば、「gotoさえ知っていれば全てのプログラムは書けるんだ」という考えは正しいよなと。実際、全てのプログラムは、最終的にはそういう形で動いているのだし。
でも、それぞれの goto には、目的があって。
- ループ処理をさせたくて、goto を使っているのか。
- ループ処理から抜けたくて、goto を使っているのか。
- ループ処理の頭に戻りたくて、goto を使っているのか。
- サブルーチンを呼び出したくて、goto を使っているのか。
- etc。
そこで先輩達は思いついた。「この goto はこういう目的で使っているんだよ、とソースにあらかじめ書いておくことにしようぜ」と。
- ループ処理をさせたくて、goto を使っているなら、「for」「while」と書いておく。
- ループ処理から抜けたくて、goto を使っているなら、「break」と書いておく。
- ループ処理の頭に戻りたくて、goto を使っているなら、「continue」と書いておく。
- サブルーチンを呼び出したくて、goto を使っているなら、サブルーチン名だけ書いておく。
ところが、今度は色んな命令を覚えないといけなくなった。今までは、goto だけ覚えておけばどうとでもなったのに…。
そこで誰かが言い出すのです。「プログラミング初心者に、こんなにたくさん命令を覚えさせるのはよくない。絶対混乱するよ…。だから、goto だけ教えとこう!」
ということで。このあたり2つの主張が成立しそうだなと。
- 「goto を覚えれば、全てのプログラムは書けるのだから、goto だけを覚えさせる・使わせるのが、初心者向きのプログラミング言語だ」
- 「goto は色んな目的を持って使われるのだから、あらかじめ、その目的別で命令を覚えたほうが混乱しない。goto を使わないのが初心者向きのプログラミング言語だ」
後者の考え方がないと、高級言語なんてものは、生まれてこなかったであろう気もしてきたり。
◎ PythonとRubyにもそういうノリを感じたり。 :
Python は、「gotoだけ覚えてればいいんだよ!」みたいなノリを感じますし、Ruby は、「何をやろうとしているか明確にしないとダメだよ!」みたいなノリを感じますな…。
例えば、「n回ループさせる」てな処理を書きたいとき。
Python なら、たぶんこうなるのかな。
Ruby なら、こうでしょうか?
Python は、range() を使って一旦配列 *1 を作って、0から4まで数値を入れて、その配列個数分取り出しながらループをしろ、てなことを指示するわけで。…プログラマーは、配列を作りたいわけじゃないのですがね。n回ループさせたいだけなのだけど、なんで配列を作らなきゃいかんのか…。しかし、Python は、「命令の種類はシンプルに」「色んな書き方ができたらダメ」という信条で作ってる言語だから、「この方法でループ処理は書けるんだからコレ使え」「コレさえ覚えとけば、配列に対して処理をしたいときも同じように書けるだろ? 何にでも使えて便利じゃねえか」で済ませてる。それは、「goto使えば全部書けるんだから、gotoだけ使え」てな思考と結構近い気がします。
Ruby は逆に、n回ループさせたいと思ってるなら、一目でそれが分かる書き方じゃないとダメだろう、という信条があるんじゃないかと。だから、times というメソッドが登場するのかなあ、と。その代わり、どんなループ処理をさせたいかによって、書き方やメソッドがどんどん変わってくる。覚えなきゃいけないことが増えてくる。…まあ、「for i in 0..4 do puts i end」「(0..4).each do |i| puts i end」みたいな書き方もできるから、この例はあまり適切ではないんでしょうけど。
Ruby を覚えた人が、他の言語を触った時になんかしっくりこないのは、そのへんが関係してるのかな…と勝手に想像してみたり。プログラマーがその時何をしたいと思っていたのか、その思考のログがソースに残りやすいのが Ruby、なのかもしれないと。他の言語は、「このソースを書いた時の俺は、こう書くことで、一体何をしようとしていたのか…?」みたいな推測作業が細かいところでちょこちょこ要求されて、それが微妙に苦痛なのかなあ、と。
まあ、自分、プログラミング言語は全然詳しくないので、実際どうなのかは分かんないですけど。
色んな言語を触ってる人なら、もっと適切な事例を出して、各思想の違いをしっかり解説できると思うので、「お前が言ってることは違うよ! 全然違うよ!」と思ったら、自身のblog等で解説してくれるとありがたいです。
例えば、「n回ループさせる」てな処理を書きたいとき。
Python なら、たぶんこうなるのかな。
for i in range(5): print i
Ruby なら、こうでしょうか?
5.times do |i| puts i end
Python は、range() を使って一旦配列 *1 を作って、0から4まで数値を入れて、その配列個数分取り出しながらループをしろ、てなことを指示するわけで。…プログラマーは、配列を作りたいわけじゃないのですがね。n回ループさせたいだけなのだけど、なんで配列を作らなきゃいかんのか…。しかし、Python は、「命令の種類はシンプルに」「色んな書き方ができたらダメ」という信条で作ってる言語だから、「この方法でループ処理は書けるんだからコレ使え」「コレさえ覚えとけば、配列に対して処理をしたいときも同じように書けるだろ? 何にでも使えて便利じゃねえか」で済ませてる。それは、「goto使えば全部書けるんだから、gotoだけ使え」てな思考と結構近い気がします。
Ruby は逆に、n回ループさせたいと思ってるなら、一目でそれが分かる書き方じゃないとダメだろう、という信条があるんじゃないかと。だから、times というメソッドが登場するのかなあ、と。その代わり、どんなループ処理をさせたいかによって、書き方やメソッドがどんどん変わってくる。覚えなきゃいけないことが増えてくる。…まあ、「for i in 0..4 do puts i end」「(0..4).each do |i| puts i end」みたいな書き方もできるから、この例はあまり適切ではないんでしょうけど。
Ruby を覚えた人が、他の言語を触った時になんかしっくりこないのは、そのへんが関係してるのかな…と勝手に想像してみたり。プログラマーがその時何をしたいと思っていたのか、その思考のログがソースに残りやすいのが Ruby、なのかもしれないと。他の言語は、「このソースを書いた時の俺は、こう書くことで、一体何をしようとしていたのか…?」みたいな推測作業が細かいところでちょこちょこ要求されて、それが微妙に苦痛なのかなあ、と。
まあ、自分、プログラミング言語は全然詳しくないので、実際どうなのかは分かんないですけど。
色んな言語を触ってる人なら、もっと適切な事例を出して、各思想の違いをしっかり解説できると思うので、「お前が言ってることは違うよ! 全然違うよ!」と思ったら、自身のblog等で解説してくれるとありがたいです。
*1: 配列じゃなくてリストと呼ぶべき?
[ ツッコむ ]
以上です。