Cだけプログラマの憂鬱

それ、C関係ないのでは - プログラミング言語を作る日記
それC関係ないよね、というのはきむら(K)さんや、id:minekoaさんにも言われたことですが、

  • 実行時のチェックがない。よって、配列のオーバーラン、不正なキャスト、開放されたメモリを参照する、といった理由でのバグが発生し、原因追及が非常に困難。
  • GCがない。
それ、C関係ないのでは - プログラミング言語を作る日記

うーん、ここは少し観点が違うかなと思います。
C++でも、配列はオーバーランするし、Cスタイルキャストで苦しむし、
解放されたメモリを参照するなんてことは日常茶飯事に起こるわけで、
これらを解決する手段として、C++では、

  • 可変長配列としてstd::vectorを利用する
  • 固定長配列としてboost::arrayを利用する
  • キャストはstatic_castだけを使う(reinterpret_castはCの構造体を読み替えるときだけ使う、const_castは使わない)
  • スマートポインタとしてboost::shared_ptrとboost::weak_ptrを使う

という手はありますが、
これも徹底されない環境があるわけで、
(前のC++のプロジェクトではこれらは一つも使えなかったですし)
GCは実用で使った事はありませんが、Boehm GCがあるので、
この辺りの論点とは違うところにあります。
これらは、そういった言語機能を愚痴ったものではなく、
プログラミングスタイルを愚痴ったものです。

void*について

void*は至る所で何かに化ける。

まあそのとおりですが、これはJavaとかでObjectを使っても同じことですね。Genericsなりtemplateなりを使えば別ですが。

それ、C関係ないのでは - プログラミング言語を作る日記

これに関しては、基底クラスを持つ言語も持たない言語も、
何かしら共通の型で扱えるようになっていることはあるわけで、
それでも、Javaは普通に存在するメソッドの引数にhoge(Object arg1, Object arg2)
なんてことはしません。
Cだって、Hoge(HogeStruct* hoge);
みたいに書けるのに、
Hoge(void* hoge);
のように、
void*で受け渡しをしようとするのか、
ということが嘆かわしくもあったりします。
Cだけプログラマはあまり型を意識したり、型を書きたがらないような気がします。(偏見


コールバックに関しても、
あるきまった関数の型をtypedefして、例えばHogeFuncitonとかFooFunctionとか
してくれたらまだ良いんですが、
大抵、こういうtypedefはなくて好き勝手受けたり渡したりしちゃうんですよね、とか。
故に、どれがコールバックになりえるのか解りづらいということになります。
callbackとか共通命名もないことが多く。

task->initFunc = HogeInit;
...





...
task->mainFunc = HogeMain;

みたいな感じに離れて配置されたりして、
うううう、とかなります。
StateやStrategyであれば、それがクラスとして存在するので遷移は読めますが、
それらが関数で散らばっていると正直めげます。


謎フラグに関しては、
ビット演算がわからない訳ではなくて、
「それが何をするフラグなのか解りづらい」ということです。
それだけではなく、構造体のメンバに一時ワークとして
work
なんて名前をつけられた日にはorzです。
これ、Cではよく見かけるので、どこか発祥の地があるんじゃないか、
とか勘ぐってしまいます。


要するに、一時変数ではスコープ上引き渡せないので、
一時ワークとして、workという変数を宣言してそこに値をいれてるんですが、
普通にその用途で名前を宣言すればイイじゃない?
絶対に生存スコープがかぶらないのでメモリが勿体ないなら、unionでいいじゃない?
とか思ったりします。
いや、sizeof(int)をけちるメモリ環境でもないですけどね。orz...


hoge->foo->bar->ptrに関しては、
C++やJavaでここまでネストしたものは見たことないんですが、
普通に、
ラップしたメンバ関数やメソッドを定義すればこんなことにはならないんじゃないでしょうか。
例えば、Hogeクラスの中にあるFooDataが持つ、FooDataControlという構造を得たい場合も、

class Hoge {
public:
    FooDataControl* fooDataControl() {
        return fooData_-> fooDataControl();
    }
private:
    FooData* fooData_;
};

とカマスだけで
hoge->fooData()->fooDataControl();

hoge->fooDataControl();
にできるわけで。
ヘルパメソッドを噛ませばネストを無用に増やすことは避けられると考えています。
ネストが蔓延するということは、無用なインターフェイスが公開されているということでもあり、
設計上問題になるわけですしね。(上記ならFooDataのポインタや参照が外部に開かれている必要性は低いと考えられる

勿論、->が.ならイイってことでもないです。


結論として、これは偏見かもしれませんが、
「Cだけプログラマは他の言語も学ぶべき」
ということなのかもしれません。
Cだけプログラマは得てして、
正規表現なんかより(よくわからないから)Cでやったら早いよ」
C++は遅いし宗教(Cのスタイルとはそぐわない)」
「GCなんて使えない(GCを使ったことがないのに遅いと信じている)」
Javaなんて使う機会がない(別にJavaじゃなくてもいいですよ?)」
とかなんとか言いますが、
プログラミングスタイルがあまりにも閉鎖的じゃないかい?
自分のために自分だけがわかる自分だけのプログラムを書いているだけじゃないかい?
なんて思うわけです。
これはCの問題ではなく、Cだけプログラマの問題なのかもと思います。まる。