2008-02-07

言語の学習とか利用とか:wtnabeの場合

※ 今回は徹底的に自分語りで行くぜ。興味なかったら無視しておくんな。言語の善し悪しを語る気はないぜ。自分の感じたままを書くぜ。

初めに断っておくと自分は Matz のような言語ヲタでもないし、基本的には C 系の言語しか知らない。関数型言語が流行ったのは知っているけど自分ではモノにできていない。Emacs を使っているので Lisp に触れる機会はあるがこれはほぼ入り口で挫折している。(一応 Gauche とか試してみてはいるんだけど)

というわけで自分はきっと世の中の言語を語る人の中では素人や初心者に近い方だろうと思う。そういう自分が少ない経験を晒すのはかなり恐ろしいことではあるのだが、PHP を使う人間の中にはこういう奴もいる、という一例として読んでもらえると嬉しい。ちなみにオチはないので期待しないように。

現在の状況

2008年2月現在、自分がよく使っている道具はだいたい以下の4つである。

  • awk
  • Perl
  • Ruby
  • PHP

※ awk は言語じゃないという意見もあると思うけど、今はそれは置いといてほしい。

Cを薦めない理由

上に挙げたものより以前にやったのは

  • BASIC
  • FORTRAN
  • CASL
  • C

である。このうち最も遊んだのは BASIC, のちに最も影響を与えたのは間違いなく C である。なぜなら awk, Perl, Ruby, PHP は基本的に C の知識の延長上に学べるから。しかし自分は C を強く薦めることはあまりしない。なぜなら自分が C を実際に必要とすることがないから。OS を書くこともハードウェアを操作することも自分ではやらないし、自分で何かを C で書くということはほとんどない。C の知識は今の自分にとって非常に有益だが、学習コストもそれなりに大きかったし、その結果「できること」にあんまり興味が湧かなかったというのが大きい。(もしかすると自分は基本的に計算機そのものにあまり興味がないのかもしれない。)

今使っている言語の中で、実際に使えるようになって最も感動を覚えたのは awk、次いで Ruby である。だから自分はこの二つの学習を薦める傾向にある。ただしこれを入り口にするのが適切かどうかは自分には判断がつかないでいる。判断はできないが根拠を示すことはできる。今回はそれを書こうと思う。

awk を薦める理由

awk は Unix の `Tools' という概念、パイプの機能と実によくマッチし、小回りの効く非常によくできた美しい道具である。もし Perl, Ruby などフルセットの言語を学習するのは面倒だが、それなりの量のデータを Excel の手作業や VBA や VBS よりももう少しエレガントに、あるいは「軽く」処理したいと思うなら awk はオススメ。行単位にファイルを読み込む、行をカラムに分割して格納するという処理を自動で行ってくれるので、自分の目的のデータの処理だけに集中することができる。

例えばデフォルトでホワイトスペース区切りのデータ

abc def ghijkl

$1 = "abc"
$2 = "def"
$3 = "ghijkl"

と自動的に毎行格納してくれる。$1, $2, … が気持ち悪いという意見はあると思うが、これは歴史的な経緯ってやつで納得してほしい。気に入らなければ自分で名前を付けた変数に入れ直して処理すればいいだけの話だ。

awk は美しい。awk に好意的な人は恐らくほぼみんな同意してくれるはずだ。awk の美しさは潔さでもある。「現実的な人間は」恐らく awk ですべてを片付けることはしない。しかし潔さは学びやすさでもある。

Perl で苦労した話

awk のあとに Perl を学んだが、やはり最初の印象は「きたねー言語だ」というものだった。この印象は今でもあまり変わらない。ずいぶん気にならなくなったけど。

いちばんはじめは、Perl の習得はあまり苦労しなかった。BASIC のような感覚で使えたから。グローバル変数は使い放題だし、サブルーチンという考え方も BASIC, FORTRAN と大差がなかった。C のような構文ではあるんだけど C と違って関数を組み上げる感じの言語じゃないんだなーという印象だった。今にして思うとこれが苦労の始まりだったんだけど。

ご多分に洩れず、だんだんと昔の自分が書いたコードが読めなくなってきた。というか油断すると昨日のコードでも意味が分からない。

package ってのがあるらしいなぁと思いつつ、今から数年前に Perl をやり直すまではお世辞にもいいコードは書けなかったし、今も書ける自信はない。(今の状態は去年の日記のまとめにその一端が見て取れると思う。)

とにかく、自分で書いといて意味が分からないコードが増えて、いやな気分を味わうことが増えてきたという印象。Perl そのものの問題ではないことは今なら分かるんだけど、ちょうど Perl をいじっていた頃がそれと重なったのでとにかくいい印象がない。ただし sh, grep, awk のスーパーセットとして目的を達成するという意味においてはやはりかなり強力で、強大だし、今後も Perl のない世界というのはまず想像できない。

ただ PHP と同じで、ユーザーがわざわざアクションを起こして守らなければならないお約束が多すぎる。こういう言語は入門には向かないと思う。気にしなければ気にしないでも動かせるが、最初に悪い作法を身につけたあとに良い作法に切り替えるのは意外と大変である。特に動くコードが出来上がってしまってから切り替えるのは殊の外シンドイ。

ゼロから自分で学ぶのではなく、カッチリしたコード資産と規約のある会社に入って学ぶのならいいと思う。

Ruby 挫折体験と Ruby を薦める理由

Ruby は一度挫折している。その理由はいくつかあって、

  • Ruby に興味を持った時期辺りから自分の興味がテキスト処理やプログラミングからいったん離れてしまった
  • 初めて書籍を買わずに習得しようと試みた
  • オブジェクト指向を意識しすぎた
  • ドキュメントの想定するオブジェクト指向の習得レベルが自分より高かった

この Ruby の学習よりも前だったか後だったか、ちょっと記憶があいまいなんだけど、概念的なレベルではオブジェクト指向は勉強していた。しかしまったくコードを書かずにはやはり理解できないもので、ふーんと思っただけだった。で、この知識だけの状態を Ruby で実体の伴うものとしたかったのだが、はっきり言ってまったく歯が立たなかった。

C++ や Java など他の、教科書の豊富な言語で少しでもオブジェクト指向を味わっていたなら話は違ったのだろうけど、Ruby はそこにあまりに自然にオブジェクトが存在するので、オブジェクト指向以前のノウハウをすでに持っている状態で「よーしオブジェクト指向を勉強するぞ」と意気込んでしまうとまったく空回りしてしまうのだ。というか自分は空回りしてしまった。

たぶん言葉の意味なんかよく分からなくても動かして納得するというプロセスをくり返せばそれでも大丈夫なんだと思う。変な色がついていなければそんなもんなんだと飲み込むことは可能だし、今は書籍を始め様々な情報も充実している。

その後、いったん Ruby を離れ、PHP をやって、その後もう一度 Perl を経たあとに Ruby に触れたのだが、今度は驚くほどスムーズに習得できた。

このとき、いちばん自分の中で引っ掛かっていたのは PHP の class 構文とオブジェクト指向である。どうも納得いかない。これが本当にオブジェクト指向か? この程度のものがパラダイムシフトと呼ばれるものなのか? 全然便利じゃないじゃんと感じ、また挙動が自分の納得できるものでなかったため、Perl で package を使ってオブジェクトを作ってみた。PHP で納得のいかなかったものが Perl で書き直したらしっくり来た。恐らくこの時点ではまだ PHP より Perl の方が自分の中で得意な言語だったんだろうし、Perl のオブジェクト指向は最初から組み込まれている機能ではないので、オブジェクトを構成する要素をバラバラにして直に手に取って見ることができる。これが本当によかった。「あぁ、こういう風にしてオブジェクト指向を実現するんだな」ということが分かった気がした。同時に Perl の書きにくさとモダンな機能のありがたさも実感できた。(このときはイマドキの Class:: 系のモジュールなどは一切使わずに全部ゼロから書いて動かしてみたのでそれなりに苦労したが、この経験は本当に大きかった。)

そして再び Ruby である。Perl であんなに苦労した部分がほとんど最初から解消されている。何もかもオブジェクトだ! そうか、Array がオブジェクトだとメソッドの引数に array のデータを入れる必要がないから引数が減るね! これで引数の順番とかくだらないことを気にしなくていいね! PHP の array_* 関数が多いのをすごいとか思っていたけどバカバカしくなるね! $this-> とか $self-> とか要らないからコードが見やすいね! < だけで継承できてめっちゃ楽だね! ! とか ? がメソッド名に使えると意味がはっきりしていいね! 動的に class の中身が書き換えられると自分のせいじゃないエラーをなくせるからいいね! 同じメソッド名なら別なクラスでもいい感じに似た動作をする ( duck typing ? ) ので、いちいちマニュアル引かなくてもだんだん Ruby の動作が予想できるようになってきていいね! てゆーかやっぱりオレは変数に $ が付くのはきらいなんだ!

本当にこんな感じで感動の連続だった。どうしてこんなにすんなりと自分の中に入ってくるのか不思議なくらい。Perl の書きにくさ読みにくさも PHP の不自由さもない世界。1.8 になってライブラリも増え、本当に楽で便利で、書くことがとても楽しい言語。それが正直な感想だ。そして薦める理由はこれだけではない。

何より、Ruby の哲学は Perl と違って優しくユーザーを拘束してくれる。「これはこうするのがいいんだよ」という使い方をユーザーに提示してくる言語なので、それに従っているだけでそれなりに良い作法が身につく。これは Perl や PHP にはないメリットである。先ほど Perl はゼロから自分で学ぶ場合にはオススメしないと書いたが、同じポイントで Ruby は初学者にオススメできると思う。(もちろん組み込みの class を破壊できるなんてのは悪い作法を身につけやすいとも言えるんだけど。)

例えば、少なくとも自分は Ruby を触ってみるまでは Perl, PHP 3/4 のようにインスタンス変数に直接外からアクセスできることにそれほど大きな疑問を抱いていなかった。アクセスしない方がよいという知識は持っていたが、実際にアクセスできることに対して疑問を抱いていないので、当然のように「アクセスできることを前提としたコード」を書いてしまっていた。これがしかし Ruby ではできない。attr_* でアクセッサを定義してやるとほとんど使用感は変わらないんだけど、「この一手間がなんかイヤ」で、だんだんインスタンス変数にアクセスできないことを前提として書くクセがついてくる。

すると今度は直接アクセスしないことのメリットに気づくようになってくる。例えば PHP では 0 が偽で、0 を返してくる関数と false を返してくる関数が混ざっているので

foo() !== false

って書かないとヤバいよ、みたいなバッドノウハウがあるわけだけど、Ruby の場合は

foo?()

のように ? で終わるメソッドは boolean を返す約束になっていて、ユーザーもこれに従うことを推奨されている。あぁそうか、PHP でも自分でそういう関数を作っていくようにすればいいんだと気づく。だから自分のコードは

if ( $val !== false ) {
}

とか

if ( hoge() !== false ) {
}

とかできるだけ書かなくてよいように、

if ( $obj->is_fuga() ) {
}
if ( $this->moge_exists() ) {
}

などで書けるように気をつけている。

もっとも、「いいコードとは」的な読み物を読むのは昔から好きだったので、ずいぶん前から「すんなり読めるコードを書くべき」というのは知識として持っていたんだけど、それが身になったのは、自分の中では Ruby のおかげである。

毛嫌いしていた JavaScript の面白さ

挙げてなかったけど JavaScript も今はかなり好きな言語の一つである。昔はうざいだけの装飾に使われている、ブラウザごとの差異がでかくて扱いにくいだけの言語もどきと思っていたけど。

残念ながらいろいろ制約があったり、ブラウザ間の挙動の揺れとか気にしなきゃいけない点が多いし、これがあればバリバリ仕事が進む!的なものではないと思うけど、WSH

  • JScript とか Widget とか JavaScript が使えると便利なシーンは増えているし、「目に見える場所」で使うことが多いので、JavaScript をいじっているときってのはだいたい楽しい。世の中のブラウザがすべて Firefox だったらどんなに楽しいだろうと思う。

まぁ愚痴はともかく、JavaScript の面白さは自分の中では Ruby の面白さとほとんど同じである。一度じっくり EcmaScript として取り組んだことがあるんだけど、このときメソッドと変数の区別がないことに多少面食らった程度でほとんどは Ruby の知識を援用してすんなり理解できた。スコープは確かにちょっと難しいけど、そこまで凝ったものをゼロから自分で書くこともないので、その辺は気にしないで済んでいる。

ちなみに好きな JavaScript フレームワークは prototype.js で、これはたぶん Ruby が好きなことと関係があると思う。Perl 好きな人や Python 好きな人はきっと違うものが好き。

PHPはぁー…どうだろう?

可も不可もあるけど、不可の方が今は目につきやすいです。

PHP を触ったときには Perl が書けていたし CGI も分かってはいたので習得自体はえらく簡単だったと思う。今じゃ当たり前すぎるのかあんまり評価されないけど CGI でも fastcgi でも mod_php でも同じコードが動くのはすごいと思った。エンコーディングの変換とかも便利だし、全体的に扱いやすくていいなと最初のうちは思っていた。

しかし度重なるマイナーアップデートという名の仕様変更の嵐に直面してすっかり印象が悪くなった。そのくせ htmlspecialchars() とか引数の追加でお茶を濁すんじゃなくて仕様を変えるべきじゃねーの、というところには変更は入らずに、PHP ユーザーである我々のコードの修正を余儀なくされるとかいうことが起きる。関数の数が多いのはいいが完全にフラットなのでやたら関数名が長く、しかも全体的に統一感がない。引数の順番はバラバラ。似たような名前の似たような機能の別な関数で引数の順番がひっくり返っているとか、あり得ないトラップがそこら中にある。

機能的には PHP は気が利いているんだと思う。でもデザインがなっちゃいない。あるだけ。アジアンテイストな部屋に北欧インテリアを飾っているようなバランスの悪さを感じる。目的は達成できるが美しくない。そういう印象。それが気にならない人には向いているが自分は正直やめられるもんならやめたい。今さらやめるにはノウハウが溜まりすぎてしまったけれど。

あと意外に困るのは Unix CLI 文化と相性がよくない点。こう言うと CLI バイナリは 4.3 から独立してて普通に使えるよ!ってムキになる人がいるかもしれないし、実際に CLI で活用している人がいるのは知っている。でもはっきり言ってこの CLI バイナリのオプションの取り方とか独特すぎる。じゃあ Windows 対応がいいかというとそうでもなくて、本家に Windows 用バイナリがあるってだけで Windows 版では実装されていない関数が意外にあったり、嘘実装の関数があったりして凹まされました。最新の 5.x 系での状況はよく分かってませんが。(Windows で動かさなくなったので。)

一言で言うと PHP は Perl や Ruby とは異なる意味で節操がない。そして数多くの便利な機能を提供してくれたが、その分多くの自動化、便利機能が Web アプリで足を引っ張ることも教えてくれた。そういう意味では非常に勉強になったとも言える。

ただ、同じ経験を「これからの人」にさせたいとは思えない。確かにブラウザに何かを表示するまでの時間は短いよ。誰かが環境をお膳立てし続けてくれるなら結構快適だ。でも使い続けさせたくないのよ。分かる?この気持ち。

まとめ

自分の場合は Ruby にたどりついて「知識が身になる」経験がとても多かったためか、Ruby の評価はけっこう高い。そして希代の言語ヲタの作った言語だけあっていろんな言語からおいしいとこどりしていることに気づき始めて、「あぁなるほどこの言語にファンがいるのはこういう理由か」なんてことが分かってくる。そういう体験もなかなか面白い。

もっとも、PHP や Perl に対するネガティブな意見の結構な割合は、触らなければいけない稼働中の Perl コード、PHP コードがイケてないことに起因しているとも思う。自分の中で Ruby の評価が高いことにおいて、「Ruby で書いてしまったクソな遺産があんまりない」っていうのは大きいと思う。これが例えば仕事で Ruby をいきなり使わされて、よく分からないけど動くコードをそれなりの数書いてから振り返ったら、Ruby よりも Java の方がよかったとか言ってるんだと思う。

また正直に言うと自分はクロージャとかファーストクラスオブジェクトとかそういうカタカナが好きではないし、ぶっちゃけよく分からない。JavaScript の function がファーストクラスかどうかなんて知らない。ただものすごく便利なものだってことは知ってて、便利なものが好きだってだけ。

だから言語の学習においてこの要素とこの要素がこういう風に入っていて、……とかそういうことは語れないし、語る気はない。こういう経験をしたワタシがこういう風に各言語を捉えています、ということしか書けない。

だから結論とかオチとかはないです。参考になるかどうかも分かりません。けど、何かの足しにでもなるといいなーと思ってます。

About

例によって個人のなんちゃらです

Recent Posts

Categories

Tool 日々 Web Biz Net Apple MS ことば News Unix howto Food PHP Movie Edu Community Book Security Text TV Perl Ruby Music Pdoc 生き方 RDoc ViewCVS CVS Rsync Disk Mail FreeBSD Cygwin PDF Photo Zebedee Debian OSX Comic Cron Sysadmin Font Analog iCal Sunbird DNS Linux Wiki Emacs Thunderbird Sitecopy Terminal Drawing tDiary AppleScript Life Money Omni PukiWiki Xen XREA Zsh Screen CASL Firefox Fink zsh haXe Ecmascript PATH_INFO SQLite PEAR Lighttpd FastCGI Subversion au prototype.js jsUnit Apache Trac Template Java Rhino Mochikit Feed Bloglines CSS del.icio.us SBS qwikWeb gettext Ajax JSDoc Rails HTML CHM EPWING NDTP EB IE CLI ck ThinkPad Toy WSH RFC readline rlwrap ImageMagick epeg Frenzy sysprep Ubuntu MeCab DTP ERD DBMS eclipse Eclipse Awk RD Diigo XAMPP RubyGems PHPDoc iCab DOM YAML Camino Geekmonkey w3m Scheme Gauche Lisp JSAN Google VMware DSL SLAX Safari Markdown Textile IRC Jabber Fastladder MacPorts LLSpirit CPAN Mozilla Twitter OpenFL Rswatch ITS NTP GUI Pragger Yapra XML Mobile Git Study JSON VirtualBox Samba Pear Growl Mercurial Rack Capistrano Rake Win RSS Mechanize Sitemaps Android JavaScript Python RTM OOo iPod Yahoo Unicode Github iTunes God SBM friendfeed Friendfeed HokuUn Sinatra TDD Test Project Evernote iPad Geohash Location Map Search Simplenote Image WebKit RSpec Phone CSV WiMAX USB Chrome RubyKaigi RubyKaigi2011 Space CoffeeScript Nokogiri Hpricot Rubygems jQuery Node GTD CI UX Design VCS Kanazawa.rb Kindle Amazon Agile Vagrant Chef Windows Composer Dotenv PaaS Itamae SaaS Docker Swagger Grape WebAPI Microservices OmniAuth HTTP 分析基盤 CDN Terraform IaaS HCL Webpack Vue.js BigQuery Middleman CMS AWS PNG Laravel Selenium OAuth OpenAPI GitHub UML GCP TypeScript SQL Hanami Document SVG AsciiDoc Pandoc DocBook Develop Jekyll macOS Node.js Vite Heroku Transformer AI Data Cloud Wasm