Linus TorvaldsのC++批判は正しかったのか 58
ストーリー by headless
主張 部門より
主張 部門より
本家/.「Was Linus Torvalds Right About C++ Being So Wrong?」より
最も有名なC++への批判は、おそらく2007年のLinus Torvalds氏の発言だろう。「C++はひどい言語だ。」彼はこう書き始める。「これをさらにひどいものにしているのは、水準以下のプログラマーが数多く使用していることで、またさらに簡単に完全なゴミを作り出せるようになっている点だ。」と続く。C++を嫌うのは彼だけではない。STLやBoostを潜在的に不安定で非効率にした原因がC++だと考える開発者も多い。しかし、C++の需要がなくなることはない。Diceの記事では、C++はそれほど嫌悪するべきものではないとJeff Cogswell氏が主張している。「実際には一度しか使用しないのにも関わらず、複数の継承を重ねて再利用可能なクラスを作成するといった、過剰な設計をこれまでに何度も目にしてきている。」と、Cogswell氏は語る。「しかしこれは例外であり、標準ではないと主張したい。適切に使用すれば、一般的なプログラミングや、C++のより高度な機能を使用したプログラミングで、大きな利益が得られる。」とのこと。Linusの発言は行き過ぎだったのだろうか。
適切に使用するのが難しい言語、それがC++ (スコア:1)
classとか設計に絡むものが言語仕様に取り込まれると、設計スキルが如実にコードに出る。
適切に使える人と格差が出やすいので、それでビジネスをする人にとって有利な言語かもしれない。
格差があれば、大きな利益を得られる訳だ。
本当の三日坊主とは、それが苦痛すぎて三日で髪の毛がすべて抜け落ちた者のことを言う。
C++に限らず (スコア:2)
一つの言語で低レベルのシステム記述から, 抽象度の高いアプリケーションまで対応させようという試みは, 古くはPL/IからAdaなど, 総じて良い結果を出したとは言えないですよね. その中ではC++はまだうまくやっている方だとは思いますが.
昔から, 銀の弾丸では無いですけど, 一つの言語で全ての用途をカバーするという欲求は強いんですが(その昔にはCOBOLで経済学的な数値解析をしたいというニーズも有ったらしい), むしろ用途に応じて数個の言語を使い分ける方が, 初期投資は大きくても最終的には幸せになれると思います.
個人的にはベースとなるCに, Lua [lua.org]の様な軽量スクリプト言語, それにPython, Rubyの様なリッチなスクリプト言語の組み合わせぐらいがバランスが取れていそうと感じますが.
Re:C++に限らず (スコア:1)
Luaなどの組み込み言語を使う用途の場合、手続き的処理を記述するのが主目的なので、
モージュール内部でカプセル化とか、ポリモーフィズムとか、オブジェクト指向言語の持つ性質は
コード中にあまり必要とされないでしょうね。
それに、組み込み言語を使うような所は、末端のエンジニアがコーディングする部分だと
思うので、言語仕様の拡張性の高さより、「必要十分なシンプルさ」といった性質の方が
メリットがありそうです。言語仕様がシンプルなら、プログラムバグの傾向も把握しやすそうです。
実のところ、カプセル化とか、ポリモーフィズムといった性質って、モジュール単位(実行プログラムやライブラリ)には既に備えている性質です。
今回はCとC++の話なので、カプセル化とか、ポリモーフィズムといった性質を
モジュールより細かいソース単位の粒度で扱いたい立場の人に対する話ですね。
なので、微妙に数個の言語の話は微妙に路線が違うかもしれません。
「あまねく関数、構造体、技術者にオブジェクトの光あれ。」と言った時、
暖かい救いのある光に感じるか、あるいは、憎しみの光に感じるか。それは経歴次第かな。
モジュール・ライブラリ単位の抽象化というのは、どこもあまり失敗しない話でしょうが、
モジュールより細かい単位の抽象化というのは、初期の段階(新規に参入する分野では特に)で子細にオブジェクト(凝集度 [wikipedia.org]、ライフサイクル、拡張性など)を考慮して、理想的な形で表現するのは難しいことですし、
それなら、構造化プログラミング的なアプローチで、適切に関数分割して、ライフサイクルは基本関数のスコープに合わせて書くぐらいの伝統的なやりかたの方がシンプルだと考え方もあるかなと思います。
本当の三日坊主とは、それが苦痛すぎて三日で髪の毛がすべて抜け落ちた者のことを言う。
Re:適切に使用するのが難しい言語、それがC++ (スコア:1)
classを普通に作るにもEffective C++またはそれ相当を読まなきゃならないのがC++。
もちろん読むやつなどいないので、むちゃくちゃなclassができる。
インスタンスをコピーすると終了時にSEGVで落ちるプログラムとか。
「コピーすることは想定していませんでした」だって。ならそう書けよ。
こういう馬鹿を想定していないのは古臭いと思う。
分かりやすくて良い?
Re: (スコア:0)
ゴミコードを増加させる例えとして良い思いますが、ポインタの功罪とも言えるので悩ましいです。
それを名言?でいうと (スコア:0)
「馬鹿とはさみは使いよう」って事ですかね
C++の規格書は1300ページもある (スコア:1)
理解するにはあまりにも大きすぎる
ひどい言語というより (スコア:0)
古臭い言語だと思う。
土台が言語仕様貧弱なC言語なのに、無理して増築した感がある。
土台から変えた言語を使うべき。
Re: (スコア:0)
土台から変えた言語を使うべき。
具体的には?
Re:ひどい言語というより (スコア:2, 参考になる)
別ACですが、Rust [rust-lang.org]が最右翼じゃないでしょうか。
C++を部品とり程度に扱い、現代の知見をもとにCの精神をそのまま残して発展させたのがRustです。
Rustは「自分の足を撃てないC」です。正しい進化だと思う。
もっとも、敷居は高いです。
Re: (スコア:0)
古臭いC言語ですがコーディングの仕方によって、例えば文章のような関数名と構造体を巧くインスタンスとして使えばC++以上のオブジェクト指向な綺麗なコードが仕上がると思います。
昔、C言語の関数名制限に8文字以下というのがあったときは、相当苦労していたでしょうね。
C++では、練りきれない仕様での無意味なクラス化とか、IDEと連携しないとメンバ関数を見失うとか、何でもかんでも標準化してみるとか、そんなことばかりやっていれば構造化プログラミング世代以下の汚いコードになるでしょうね。
# ファイル拡張子をcppと書いて内部ではCで書いている私です
# ガンプラはどう作ろうと自由だ
Re: (スコア:0)
C言語でも、C89で書かれたコードは微妙ですね。GNU拡張の一部が取り入れられたC99は綺麗なコードが多いですが、長年Microsoftが未対応を貫いていてC99普及の障害となっていました。
# 最近やっっっっっっっっっっっとC99に対応しました>Microsoft
Re: (スコア:0)
C99 には失望した
Re: (スコア:0)
微妙な部分もありますが、それでも指示付き初期化指定子(Designated Initializer)は現代に於いて不可欠です。
Re: (スコア:0)
> 古臭いC言語ですがコーディングの仕方によって、例えば文章のような関数名と構造体を巧くインスタンスとして使えばC++以上のオブジェクト指向な綺麗なコードが仕上がると思います。
C言語で書いオブジェクト指向のコードって、関数ポインタだらけなイメージなんですが、
C言語で書いたC++以上のオブジェクト指向な綺麗なコードっていうのが、
どんな感じなのか、参考になるURLとか教えてもらえると嬉しいです。
> C++では、練りきれない仕様での無意味なクラス化とか、IDEと連携しないとメンバ関数を見失うとか、何でもかんでも標準化してみるとか、そんなことばかりやっていれば構造化プログラミング世代以下の汚いコードになるでしょうね。
コードが汚い云々は言語仕様よりも設計、コーディングする人次第っしょ。
Re: (スコア:0)
AC(#2777520)です。
> C言語で書いオブジェクト指向のコードって、関数ポインタだらけなイメージなんですが、
まあ確かにそうですね。 constやrestruct修飾子を巧く使えば、最近のコンパイラがある程度のミスを見つけてくれるのは助かります。
ポインタを使うことによる危険性も確かにありますが、コンパイラに全て任せて良いのかとの懐疑的であったりします。まぁ、任せたほうがコーディング的に楽ですが。バッファとかをSTLで確保した場合、いつ開放されるかはSTLの実装次第なので、やはりある程度はプログラマも認識は必要だと思いますね。あ、C++11では開放タイミングが指定できるようになったんでしたっけ。
昔、こんな提唱
Re: (スコア:0)
ありがとうございます、C-language's Object Oriented Language はかなり前に見た記憶があるような、ないような。
デバイスドライバの方は、ビルド中にチラ見してましたが後でゆっくり見てみます。
リソース解放タイミングの指定はもともと出来ていると思ってますが、多分自分が思ってることと、
AC(#2777520)さんが言ってることに違いがありそうな気がするな。
Re: (スコア:0)
Cは行間が読めない言語
C#は行間が読める言語
Cの仕様を引きずるC++、Objective-Cは前者。
Javaはどちらかといえば後者だが冗長的な記述が多くなる傾向がある。
PHPなんかも型の扱いが大らかすぎて前者。
SwiftやScaleはまだ触ったこと無いので除外
但しC#でもクエリ式はダメ
間違っている (スコア:0)
LinuxはひどいOSだ 水準以下のユーザーが数多く使用していることで、またさらに簡単に完全なゴミを作り出せるようになっている点だ
とも言えるわけだしな
問題なのは水準以下のほうだろう
批判するならカーネルに使われてるC言語はどうなんだ?
あれだって水準以下のプログラマーが作ればひどい魔物に成長するものだ
Re: (スコア:0)
Cはそれでも枯れているからじゃね?
と爺プログラマは思っているだろう
あと言語にfail safeが取り込まれていない言語は若者は取り込みにくいだろう
Re: (スコア:0)
今時はC言語なんてわざわざ使う人に水準以下の人なんて少ないんじゃないか?
Re: (スコア:0)
それ言ったら今時C++を使う人なんてって話にならないか
Re: (スコア:0)
どっちも凶悪な魔物が作られるけど倒しやすい方といえば経験則的には…う、うーん。どっちも大変だな…
Re: (スコア:0)
考えてみると、「メンテナンスさせられた経験」が、その言語のイメージに強く関わっているようなw
Cってアホみたいに巨大な関数書いたり、機能してないコーディング規約を遵守(読み辛さに貢献している)してる
コードを扱った思い出ばかりで、すこぶるイメージが悪い。
当然全てのプロジェクトがそうではないのだけど、なんかPHPに似た精神のプログラマがそこそこいた気がする。
C++はなんだかんだで、関数は短くしよう、プログラム部品は一定の単位に整理して管理しようという
常識は感じるプログラムが多かったので、ハマる事はそれなりにあっても許せるレベルだった。
Re:間違っている (スコア:1)
>機能してないコーディング規約
再帰呼び出し禁止→スタックのことを考えれば、やむなし
goto禁止→分からなくもないが、エラー処理にはgotoが欲しい
関数末尾以外のreturn禁止→理不尽
Re: (スコア:0)
continue 禁止ってのも見たことある。
Re: (スコア:0)
言語的な問題じゃないけど。
初期の(だと思うけど)ソースコードデバッグで関数シンボル名が無茶苦茶で投げた経験からC++は受け付けなくなった。
水準以下のプログラマによるゴミの生産量で言うと (スコア:0)
実際に自分が目にした範囲で言えば、Javaが随一だと思う。
まぁ、それほど多く使われているからって部分もあるけど。
Re:水準以下のプログラマによるゴミの生産量で言うと (スコア:2, 興味深い)
確かにJavaのプロジェクトはひどいの多いし、Javaに低レベルな技術者もっていかれるからC++にはそれなりのPGが揃うんでC++のがマシに見えるかもしれない。
でも、本気のC++のヤバさはそんなもんじゃないよ。一瞥して謎の言語に見えるほど別物になることもあるし、普通に見えて至る所罠だらけで簡単な修正が予想外の影響を引き起こす怪物にもなる。
printfは非効率だとおもう (スコア:0)
iosreamの是非は置いといて
ループの中にィテラル書式のprintfが鎮座とか邪悪なコードを最短距離で構築できるのはC言語の方だろう
Re: (スコア:0)
型安全じゃないしな
Re: (スコア:0)
でも、iostreamの遅さを見るとなぁ…
Re: (スコア:0)
高々十数文字程度の文字列を処理するのに、いまどきそんなに高コストな処理なのか?
Linus氏の見解の日本語訳 (スコア:0)
taro-nishinoの日記: Linus氏のC++に対する最近の否定的見解
http://slashdot.jp/~taro-nishino/journal/509450/ [slashdot.jp]
Linus氏のC++否定論は、C++というよりも、オブジェクト思考言語全般に当てはまります。読まずに批判・評価する人は、まず読みましょう。
例えば、Linus氏はこういうことを言っています。
「良いコード設計は、いかにデータが移動するか、いかにデータを秩序立てるか、いかにデータを見つけ、他のデータと関連付けるか、について考えが次々と思い浮かぶ。
だが、OO言語は、オブジェクトが重要であり、オブジェクトに関連付けられたメソッドを持つべきだという手段を考える傾向にある。まさに馬鹿げた話だ。一つのオブジェクト(又は、ある型のオブジェクトの当り前なコレクション)が本当の関心事ではない。
関心すべきは、異なる型の異なるオブジェクトが相互作用し、ロッキングルールを持つ等々の時なのである。その時点で、重要なのは一つのオブジェクトではもうないのだから、"オブジェクトインターフェイス"を隠蔽しようとするのは絶対に間違っている。」
Re:Linus氏の見解の日本語訳 (スコア:1)
本来のオブジェクト指向のオブジェクトは、メッセージの送受信により処理を定義するものなので、プロセスやスレッドに近い。
オブジェクト=スレッドを明確にしたのが並列処理のアクターモデル。
大抵のオブジェクト指向言語のオブジェクトはメソッドが定義できる抽象データ型で、f(obj)をobj.f()として書けるシンタックスシュガーのようなものだから、
オブジェクト指向的な設計を行っても、メッセージ送信が関数呼び出しなので、手続き的に密結合になって、並列処理との相性が良くない。
Re:Linus氏の見解の日本語訳 (スコア:1)
リーナスにしろ、ストールマンにしろ、なんでこう攻撃的で過激なことを言っちゃうんだろう。
コンピュータの自由を守るためには、これくらいの攻撃性は必要なのだろうか?
Re: (スコア:0)
>"オブジェクトインターフェイス"を隠蔽
これは何を言いたいのかさっぱりわからん。
インターフェイスは隠蔽すべきでないし、むしろ積極的に明確にするのが普通。隠蔽すべきは、実装などの詳細部分。
Re: (スコア:0)
言ってることが逆だよね。
OOはオブジェクトそのものが重要ではなく、インターフェースやオブジェクト同士の関係が重要となっている。
OO (正確にはADT)より前は、データの中身やその表現方法などが重要だった。というか、インターフェースなどの上位層とその層を明確に分離できてなかった。
Re: (スコア:0)
リファクタリングの話のときにもあったけど、
Cだと
をオブジェクト志向だと、
にするのが気に入らないってことでしょ。コンパイラにとってはともかく、カプセル化することによって、わかったようなわからないような感じになる。
Re: (スコア:0)
並列プログラミング時代に重要なのはデッドロックを防ぐためのロッキングルール(AB-BAデッドロックを防ぐためのロック階層)を正しく保つことにあります。
オブジェクト指向の問題は、振る舞いの隠蔽によってロッキングルールの守られているかが見えにくくなっていくことにあります。
Re: (スコア:0)
とても良くわかる解説ありがとう。
そういう手続き的な何かをOO的な何かに入れ込んで保証しまおうとすると
偉い大変でむちゃくちゃになるというのはわかる。
それをOOの人は適切に判断できないということかな。
Re: (スコア:0)
> When it gets interesting is when different objects of
different types interact, and have locking rules etc. And
at that point, trying to encapsulate some "object interface"
is absolutely the wrong thing, because it's not about a
single object any more.
「オブジェクトインターフェイス」"を"ではなく、"に""へ""で"隠蔽といったところでしょう
Re: (スコア:0)
どこに付けるか迷いましたけど
Linus氏のいう所のオブジェクトは(C++は詳しくないので)Javaでいう所のインスタンスの事です、多分。
Cより粒度の荒い中途半端なクラスしか作れないくせに、メモリ上で直接操作できないようになっている、
そして言語仕様でクラスやその他の構文によって意味的には記述できても機能的にはよく分からない事をしている。
だからシステム記述言語としては相応しくないと。
それ以外の事に使うのならVM系言語である機能が無いのでCもどきであるC++である必要は無いので有り得ない。
という話だと思われます。
Re: (スコア:0)
>Cより粒度の荒い中途半端なクラスしか作れないくせに、メモリ上で直接操作できないようになっている、
どういうこと?
Re: (スコア:0)
クラスやテンプレート、継承の構成をバイナリレベル(ポインタ)で弄る事が出来なくて言語仕様化してるとこ
クラス内の関数や変数のアドレスを置き換えるって多分出来ないですよね
日本語訳を見るとオブジェクト指向が悪いというよりは全てを実装出来ていない中途半端なオブジェクト指向で
結局は規定のクラス群の組み合わせだから、何でも出来るC言語でいいだろという主張に見て取れる
その方が分かり易く問題も少ないという話だと
Re: (スコア:0)
>「良いコード設計は、いかにデータが移動するか、いかにデータを秩序立てるか、いかにデータを見つけ、他のデータと関連付けるか、について考えが次々と思い浮かぶ。
これが、作った人にしか思い浮かばないから、OOPを使うんだと思うけどな。
行為主体 (スコア:0)
行為主体が物ではなく人間(コンピュータ)なのだから、
「AがBと何々する」
より
「私がAとBを何々する」
と言う記述が人間には自然でしょう。
よってオブジェクト指向的記述はいまいちだと思われます。
Re: (スコア:0)
それはoopの問題ではなく
interface 私 {
void 何々(A a, B b);
}
というように設計すべきという話ですね。
そしてコンピュータは人間ではありません。
Re: (スコア:0)
サブジェクトじゃなくてオブジェクトだよ。「AがBと何々する」と言うと理解がそもそもおかしい。「Aに対してBを利用して何々する」と言うのがより正確。
だったら「Aに対してBを加える」ということ。分かりにくいのは、その結果をAに代入するのか、値を返すのかがこの表現からは分からないということだ。その辺りは、
のように書ける言語であれば、(少なくともそういう言語を使っている人には)より明確だ。それでいて、これもまた、オブジェクト指向的表現である。関数呼び出しに関しては、第一引数を書く場所の違いに過ぎない
では、何がオブジェクト指向的じゃないかと言ったら、
継承ではなく (スコア:1)