プログラミング言語の簡単さ/むずかしさ
Scala をディスると PV が増えると聞いて。Scala、難しいよね(棒読み)。
そういう冗談さておき。プログラミング言語が簡単/難しいって何だろう。
How vs. What
C# もよく言われるんですよね、「C# は簡単だ」というのも、「C# は難しい」というのも両方。で、よくよく話を聞いてみると、だいたい以下のような感じ:
- C# は文法が多い。概念覚えるのが大変だから難しい。
- C# はやりたいことをやれるから簡単。
文法の簡単さ
「プログラミング言語マスター = 文法を覚える」だというなら LISP でも使ってなさいってば。あの言語、超簡単ですよ。() の中にトークン並べるっての以外に何も文法持ってないから。
こういう意見って、要するに、How(どう書くか)ベースの簡単さなんですよね。
やりたいことをやる簡単さ
プログラミングって手段であっても目的ではないわけで。What(何をしたいか)ありきだと思うわけです。
さて、そうなると、プログラミング言語の文法が少なければ簡単かというと、if とか for とかを書くのがあなたの目的ですか、と。
というか、この意味でいうと、「簡単さ」という言葉に占めるプログラミング言語文法の割合なんて大したことはなくて、ほとんど、ライブラリとかフレームワークの方に依存するのではないかと。
文法なんて、覚えることも少なければ、ここ数十年での進歩の度合いも大したことはないです。C# みたいに、たった10年でずいぶんと進歩した言語でみても、フレームワークやライブラリの方の追加・進歩と比べると大したことはない。
理不尽な難しさ
「難しさ」にも、必要に迫られてどうしようもない必要悪的なものと、意味もなく単に難しい理不尽なものとあるわけで。
と言っても、好き好んで理不尽な難しさを導入しようなんて人は、通常、いないわけで。ネタ言語ならともかく、少なくとも実用を目指すものならば。
理不尽な難しさって、だいたいは歴史的背景に起因するか、思慮が足りなかったかのどちらかで。
歴史的背景
まあ、できた当時の事情を考えればしょうがない。どうしようもないものの…
C++ の理不尽の大半は、歴史的にどうしようもないものが多く。
C#、たった10年しかたってないこの言語ですら、もはや黒歴史と言っていいものもあり。
特に、古い文書はいつまでも残る
今はさすがにもうって感じですが、C 言語って、長らく K&R の呪いみたいなものに悩まされ続けてたり。ANSI 標準化前の初版のスタイルで C 言語を覚える人が続出してしまったという。
そんなに頻繁に更新のなかった C ですらそんなので、まして、発表から10年、正式リリースから8年にしてバージョン 4.0 の C# なんてもう。ほんの少し昔に自分で書いた説明ですら「あっ、古い。このコードまねないで。」と思いつつも、直す時間取れない/メディアの都合でそう簡単に直せないものがどれだけあるかっていう。
思慮の足りなさ
だいたい、問題は後からでてくるもので。
これに対する解決策は、十分な試用期間を設けて、十分な人数で使ってみて問題を洗い出すこと。
となると、Java とか C# みたいに最初から企業の後ろ盾のあるものはともかくとして、個人ベースの開発から始まって、徐々にコミュニティが成熟してきたような言語は何かしらカオスを抱えてしまうもので。
個人的には、Scala にもやっぱりこの手の理不尽が少々あると思っています。
簡単さ/難しさ の要因
もちろん、ライブラリの充実、言語機能の充実。そして、前述の「理不尽」が少ないかなどもありますが、その他にも。
検索性
ライブラリやらフレームワークやらの挙動まで含めれば、プログラミング言語のすべてを覚えきれる人なんてほとんどいないわけで。ソフトウェアに求められる要望も多ければ、言語やライブラリが持つ機能も膨大な今、大事なのは機能の探しやすさではないかと。
目次検索
膨大な数の機能を、名前空間(パッケージ)とかクラスで分類・整理できた方が「簡単」だと思います。
「書くのが楽だから」とか「クラスって概念を教えなくてもいいから」って理由で、標準ライブラリをグローバル関数だらけにしてしまうと、検索性で非常に困ることになるかと。IntelliSense とかのコード補完機能で、補完候補が100個くらい出て来るともう、それは補完の価値半減。
検索エンジン
検索エンジンでの検索性でいうと、記号をやたらと使う言語は不利ですね。
その点、関数型言語というか、エンジニアじゃなくて数学者に媚びた感じの言語はつらいというか。
一貫性
他の文法との
文法が一貫してないことってそうないというか、一貫してないのは前述の「理不尽」にあたるはずですけども。
他のライブラリとの
まあ、新しいライブラリを使い始める際、使ったことのある既存のライブラリとの類推を求めるもので。
この辺り、標準ライブラリが強ければそれに合わせるサードパーティが多くなるとか、言語機能が充実していれば独自にデザインパターンの亜種実装しなくていいとかあり。
C# の楽さはこういうところにあると思う。snake_case, camelCase, PascalCase が混在すること少ないし、イベントハンドラーの登録口は普通eventになってるし。
他の言語との
例えば、.NET 言語なら、今となっては、「匿名メソッドとか作ったら Action か Func になる」というのを期待しちゃうんですよね。それが標準だから。でも、これが、F# だとそうならない。FSharpFunc とかいうクラスになる。
カリー化の都合とかだとは思うんですけど、こういう細かい独自路線が、「他の .NET 言語からの流入」を結構妨げてると思うんですよねぇ。
必要十分性
機能は多ければいいかというとそうでもなく。理想をいうと、目的に応じて、目的を達成するのに必要十分な量が一番簡単なわけですが。
この辺り、目的を絞れない汎用言語は不利。かといって、いちいち目的特化型の言語(DSL)を作ると、いちいち文法を覚える手間もかかるわけで。
結局、汎用言語+DSL の混在開発を目指してみるか、せいぜい目的ごとに名前空間をきっちり分類して検索性を上げるかくらいしか手の打ちようもなさそうな。
注意点
目先の簡単さ
世の中、「短期的に見ると簡単なんだけど、長期的には負債にしかならない」っていう罠だらけ。
そりゃ、setter/getter 書くよりも、フィールドを public にしちゃう方が楽よ。その場は。
そりゃ、デフォルト引数とかあると、オーバーロード書かなくて済むから楽よ。バージョニングの問題さえなければ。
そりゃ、イテレーターとか書くよりも、入力・加工・出力を全部1つのループの中で書く方が楽よ。後々、ループの規模がでかくならなければ。
パット見の簡単さ
概念も難しくない、書くのも簡単。でも、絶対はまるなんてものも。
例えば非同期処理、特に同時実行制御(ロックとか)なんかがその最たるもので。意外と、同期コードって単純に見えるんですよね。コード上は。
でも、同時実行制御の本当のヤバさはテストにあって。100万回に1回しかでないバグとかざらで、どうやってテストしろと。チェックインのたびに100万回テスト走らせるの?確率論的に「100万回に1回」なとき、1,000万回走らせても出ないときはでないよ?
慣れによる楽さ
自分は C で覚えたから C にある機能に近いことだけ覚えるのが楽。諸先輩がみんな C だから、新人も C 教えるのが楽。そういう楽さはあるのでなんとも。
そしてレガシー化。