SSブログ

JavaScriptに見るプログラミングリテラシー [プログラミング]

題は難しげですが、大した事は書きません(書けません)ので。

ある時、あまりプログラミングをしないコボラーのSEの友達が、JavaScriptの話をしてきた。文字列同士を足し合わせると、文字コードの足し算で別の文字列になるんじゃないか、と言っていた。最近の普通のプログラマの考えからすると、文字列を+で足し合わせると、連結というのが常識だと思う。

友達が何のはずみでそんな事を言ったのか忘れたけど、その時は何をトンチンカンなことを言っているのだろうと一笑に付した。でも、良く考えるとその理由は人を馬鹿にできるものではなかった。まぁバカにしていたわけじゃないが、何でそういう発想になるのかが理解できなかったのだ。でも、理由がわかった。その友達は週末に会う約束があるのだが、その時の話のネタが減っちゃうな。まぁいいや、重ねて話して発展させる方向で。


 
多くのプログラミング言語では

 "abc" + "xyz"

の結果は

 "abcxyz"

になると思う。昔のPerlとかで"abc"."xyz"みたいに変態な書き方をするのはおいといて、大体の普通の言語で連結するのは+だと思う。実に明快で分かりやすいコンセプトで、コンセンサスのとれた文法だと思う。JavaScriptではString型のオブジェクトでも、プリミティブの文字列でも、足し算をすると連結することになる。

やってみればすぐに分かることなのだが、友人はソースを見ていただけだろうと思われる。そして、多分、そのソースを見た所が、文字列同士を比較していたのではないかと推測した。会う時に聞いてみようと思うのだが、そうじゃなかったらヤダなぁ。

 "abc" < "xyz"

この結果でtrueが返る。だから、文字コードの数で比較してて、文字列の足し算をする時もそれが効いてくるんじゃないかと思っていたんではなかろうか。というか、それ以外には考えづらい。

ちなみに比較した時の大きさの順番は、
 数字<アルファベット大文字<アルファベット小文字<ひらがな<カタカナ<漢字
だった。いわゆる辞書式ですね。それはRubyでも同じなので一般的な傾向だと思われる。参照元は以下。

プロになるためのJavaScript入門 ~node.js、Backbone.js、HTML5、jQuery-Mobile (Software Design plus)

プロになるためのJavaScript入門 ~node.js、Backbone.js、HTML5、jQuery-Mobile (Software Design plus)

  • 作者: 河村 嘉之
  • 出版社/メーカー: 技術評論社
  • 発売日: 2012/12/07
  • メディア: 大型本


C言語だって単体のchar型じゃないと計算にならないんじゃないかな。文字列はchar[]だから、足し算するとポインタ同士の計算とかになっちゃうか? そうだとしたら、明らかにinvalidなアドレスを指してしまうね。結局、C言語だとstrcat()とか使うんだっけ? しばらくやってないので忘れた。

最近JavaScriptを勉強していて、文法的には名前の通りJavaっぽいところもあったのだが、似て非なるものであることがはっきりしていった。特にオブジェクト指向の方向性的に違う部分が大きくて、なし崩し的に拡張していった元々の部分と、ECMAScriptの齟齬が気持ち悪さの核になっている気がする。

とはいえ、文字列を比較したり、文字列を足したりする行為は、オブジェクト指向ではプログラミング言語全体(古いのは抜かして)でのコンセンサスとなっており、挙動も大体一緒なのだ。そういのはプログラミング言語を学ぶ時のリテラシーとして理解していた方がいい。でも、複数の言語をきちんと習得している人間ってのは少ない。私みたいに仕事の都合上、場当たり的にいくつもやっている人はゴマンといるだろうけど、全部きっちり覚えているかと言われれば答えはNOだ。というか、ひとつでも精一杯なのに。




ただね、JavaScriptだけが気持ち悪い言語ではないんだよね。過去の例を鑑みて作られているRubyにしても、相当筋のいい作られ方をしているにもかかわらず、ちょっとすんなり入らないところはある。

例えば、イテレータとかリソース管理の時に使うブロックがあるんだけど、do endと{ }で囲む方法がある。本を読むまで頭の中ではっきりしてなかったんだけど、ふたつある意味があったのだった。直接的には、演算子の優先順位って事なんだろう。演算子の優先順位ってのは、プログラミング言語の説明で必ず表で出てきて、大抵すっ飛ばして読むところ。具体的にはaとbをかけてから、cをかけたい場合、

 a+b*c

じゃなくて、

 (a+b)*c

としなくちゃいけないとか、実行する順番の事です。C言語ではテクニカルな書き方をいくらでもできるようになっているので、変態なコードが量産される傾向にあったのですが、誰もがバグの元になるのを嫌って、goto文的に忌み嫌う人も多いと思われます。相変わらず、後のメンテを考えないオナニークズプログラマはいるんだろうけど。とにかく、自分でしか使わない物以外は、読みにくくて理解しづらい直感的なソースではない、おもくそ演算子の優先順位に依存する物なんて作っちゃいけない。

それでdo endと{ }は、結合強度が違うらしく、場合によっては実行する順番が違ってきたりして、挙動が変わってきてしまう事もあるという。例示出来ないのが、ヘタレで済まないと思うのだが、Rubyのコミッターの人がとっさに判断がつかないぐらいの事項ではあったりするらしいので、直感的な状態ではないと言う事はできるのだろうと思う。詳しくはこの本で確認してください。

初めてのRuby

初めてのRuby

  • 作者: Yugui
  • 出版社/メーカー: オライリージャパン
  • 発売日: 2008/06/26
  • メディア: 大型本


語句的に説明が足りないところもあるけれど、5年前の本としては1.9も対応しているところもあるので、まだ読めると思います。まぁRuby2.0でちゃったけどね。薄い本なので読みやすいし、ガチな(Rubyが始めのプログラミングである前提の)入門本では端折られる部分がわりと書いてある。何の前提もなくリテラル記法とか言われても正確には分からんだろう。当然、その語句の説明はない。まぁWebで検索しながら読めばいいんだろう。詳しい副読本はあった方がいいんだけど。


Rubyでいうとその他には、配列の添字代入式と添字参照式の挙動。って分かりにくいから例示。
array = [0, 1] 
p array[3]     #添字参照式 nilが出てくる。エラー的な対応? arrayは[0,1]のまま
p array[-3]    #nilが返る。
array[-3] = 3  #IndexError: index -3 too small for array; minimum: -2とエラーになる
array[5] = 4   #添字代入式 代入される際、間の指定されてない配列にはnilが入る[0,1,nil,nil,4]

Rubyでは配列の添字に負の数をとる事ができるんだけど、今回はそれじゃなくて代入と参照が同じ書き方をしているのに挙動が違うという事。

おいらは気にしなかったんだけど、上の本では変なところがあると示唆している。「添字参照式が返す値は配列が持っているオブジェクトへの参照であり、それと同じ記法に式を代入するってのは訳が分からない」、とあります。C言語で言うなら、文字列のポインタに意味のない数字を入れるとか、そういう程度の事だろうと思う。

でもオブジェクト指向で演算子の再定義が出来る事を考えれば、まわりの演算子などの状況に対応して、オブジェクトの挙動が変わるってのは珍しい事ではない。とはいえ、参照云々ってのはオブジェクト指向では基本だから、気にしておく必要はある。というか、今時値渡しなんてオブジェクトじゃないプリミティブなデータ(まっさらな数値だけとか)しかないのだろうが。とにかく、

添字参照式 Array#[]
添字代入式 Array#[]=

と別なメソッドを呼んでいる事になるので、物としては全く別のモノになる。上に示したように、-3などの負の添字でアクセスすると、エラーになったりnilが返ったり違う側面が見えてくるわけだ。だから、代入や参照ですら見た目の挙動が違いますよ、という事をある程度は前提にしておかなければならない。それを前提にしたくない人は、C言語でポインタを使って、*を付けたり付けなかったりで制御してよねってことなんでしょうね。

そこいらは、C言語を見ると、機械的に判別しやすい書き方ではあるが、人間的には代入しているのも参照しているのも、書き方で理解できる範囲であるから、同じ書き方で出し入れできた方がいいよね、っていうプログラミング言語のコンセンサスであり、流れなんだろうと思う。少し、機械的に判別が面倒にはなるけど、どうせオブジェクトごとに演算子を再定義しないといけないんだから、その辺も一緒に処理に組み入れてしまおうというのは、至極当然な成り行きなんだろうと思う。




このように、その人のそれまでの経験によって、プログラミングのリテラシーは大きく変わる。長い間同じ言語をたずさわってきていても、常識は違うくらいだし。前にC言語を主にやってきた人に

#if 0
#endif

で、長いコメントアウトをしますよね、と言ったら、「は?」とか言われた事があって、この人モグリかと直感した。少なくとも制御系のソースを引き継いで使っていれば、そういう今までのソースを残しつつ、コメントアウトしてやるというのは必然性がある。その人は/* */でコメントアウトすれば済む程度の改変しかしてこなかったのかもしれないが、/* */では多重にネストできないから、規模が大きくなるとマクロでコメントアウトするのは必然的になってくる。

彼は小さなプロジェクトしかこなした事がないのかもしれない。ある程度の継続されて改変されているソースを扱っていれば見た事がない事はないはずだ。まぁ仕事経験でしかプログラミングしているのであれば仕方ないのであろうなとは思うけど、その年で知らないとかあり得ないとか思った。そういうヤツに限って、人をバカにするような事を言うのだ。それは他山の石にしたいと思ったが、この件については職業プログラマとしてはアウトだと思った。


そのくらい常識というものは人の努力や経験によって違う。プログラミングとはいえ言語なんだから同じ事が通用するとは思わない方がいい。やり方の導入にする事はいいが、思っているのと挙動が違ったら、正確な情報を確かめた方がいい。変に自分で曲解してしまうと、あとあと酷いしっぺ返しがくる事もあるから。

だから、文字列の足し算で連結じゃなくて、文字コードの足し算であると考えるのも、言語自体の初心者ではさして珍しい事ではない、と考える事も出来る。程度の違いはあれ、ある程度は自分の理解内で把握し、理解しないといけないのだ。でも、実際の挙動を見る事も大事で、座学的に学ぶのもいいけど、手を動かして学ぶ事も大きな経験となるのは間違いない。





ここまで言っておいてなんだが、積極的なプログラミングの拡張は、一般的な常識を超えてもいいと思う。もちろん、それがコーディングする時にバグの元にならない上に、便利であるという前提に於いてだけど。例えば、先に見た例のコードだけど、既存の配列に指定した配列の添字が1以上離れている時に、間の配列の要素にnilがパッディングされるように入るっていうのは、知っていれば楽できる。知らないと途中でnilが入ったところを参照しちゃったりするんだろうけど、それは「言語仕様を知らない+そもそもの論理的なミス」であり、nilのパッディングは有用であるから導入を決めたのだろうと思う。Rubyにはそういう楽天的な改善が多く見られる気がする。そういうところが、日本みたいな英語が出来ない人が多い国のプロダクトなのに、世界的に指示されている理由だと思われる。

Rubyの成長を目の前にして、言語もどんどん変わっていくのだなぁと思い、下位互換性が無くなるまで変えるっていうのは大変な事だと思った。そういう意味でもRubyは筋がいい方だと思ったよ。その他にC言語くらいしか、きちんと習得していないし、使い始めた当時には既にもう固まっていたような物だった。だけどRubyに関しては、それまでの言語をきちんとふまえた上で、書き方が便利というものすごい成長を遂げたのは素晴らしいの一言だった。

とはいえ、まつもとゆきひろさんは1.9以降を他の人に譲り渡して、mRubyとかいう組み込み系の地平を行き初めてはいるんだけど、どこまでも先をいく事を止めないんだなぁと感心します。そこまでのスキルがないから、どういう心境かは分からないけれども、先に行きたいという気持ちを維持するのは大変な事だとは思います。でも、その大変さを大変だと思わない気持ちも少しは分かる気もします。困難だからこそ、簡単に便利に視界をクリアにしたいという気持ちは同じ何じゃないかな、と。

それに比べてJavaScriptはちょっと酷い。みんなが使うにはクセがありすぎる。

タグ:Ruby JavaScript
コメント(0) 
共通テーマ:パソコン・インターネット

コメント 0