見出し画像

Retro-gaming and so on

C言語脳と言う病理

教えて!gooの方で「とんでもない質問」が投稿されていた。
いや、質問者が「とんでもない」んじゃない。その人が参考にしてた「C言語独習サイト」ってのがとんでもないんだ。
例によってリンクは貼らん。個人攻撃が好きじゃない、ってのが1つ。
もう1つは、「リンクなんぞ貼っちまって」有名になってしまえば「被害者が増える」と思ったからだ。
プログラミングを学ぼうとする初心者は「何が良くて何が悪いか」分からん。
従って、



とすると、「メジャーなサイトじゃないまま」埋もれてて欲しい。
そしてかなり「デタラメ」書いてるんで、信用出来ないんだよ。
そういうわけで、晒す気にもならず、リンクもサイトの名前も紹介しない。

さて、まずは、「何がとんでもなかったのか」。
ビックリするのが、オブジェクト指向言語じゃないC言語でオブジェクト指向っぽいプログラミング法を紹介してる辺りだ。トチ狂ってる、と言える。
オブジェクト指向を理解するにはオブジェクト指向言語を使うべきだ。当たり前だろ。
件の質問者が悩んでたのはC言語の機能じゃない、んだ。どうしてそういう風にプログラムするのか、が分かってないんだ。これも当然だろ、って思う。
どうしてプログラミング初心者が「オブジェクト指向」の概念を知らずに「オブジェクト指向っぽく」プログラミングが出来る、って考えてるのか。あったまおかしいんじゃねぇの?ってのが正直な感想だった。
ただでさえオブジェクト指向は分かりづらい。その分かりづらいものをどうして使うのがクソややこしいC言語で学ばなアカンのだ。
アイディアを把握してないのに、どうして実装「だけ」で説明出来ると考えてるんだ。アホか。構造体使ったり構造体へのポインタ使ったり・・・とか実装テクニック上の話になって、本筋見失うのは当たり前だろ、っての。
C言語っていっつもそうなんだよ。「大枠のアイディア」じゃなくって実装法の話にすり替わるんだ。二分探索木の話した時書いただろ?二分探索木の「アルゴリズムを学ぶ」のと「構造体を用いた実装」は全く関係ないんだけど、C言語だとアルゴリズムの話なのか、実装法の話なのか、ごちゃまぜになって分かんなくなるんだ。

勘違いして欲しくないんだけど、「C言語でオブジェクト指向っぽくプログラミングが出来ない」って言ってるわけじゃない。実例もあるしな。Linuxでのデスクトップ環境で有名なGNOMEはC言語で書かれている。しかし「オブジェクト指向っぽく」プログラミングされてるのは有名な話だ。
ただし、だ。それが可能だったのはGNOMEをプログラミングした人たちが「オブジェクト指向を熟知してたから」に他ならない。そういうC言語エキスパート達がC言語を使ってオブジェクト指向っぽくプログラミング出来たから、ってズブの素人が「同じ事が出来る」ってどうして考えられるんだろう。むしろタダでさえオブジェクト指向って概念が分からんのに混乱するだけだ、ってどうして分からないんだろう。
ただでさえ「理解が難しい」オブジェクト指向。「オブジェクト指向じゃないプログラミング言語」でオブジェクト指向を理解させよう、なんざアタマのおかしい無理ゲーでしかない。案の定、質問者は「実装法の枝葉末節」で「何故?」になっていた。モデルの概念が分からないのに「どうしてそういう実装をするのか」分かるわけがない。当たり前だ。マジで「バッカじゃねーの」とか提示されたサイトの記事を読んで頭痛を覚えてたんだ。

ところで、僕が「オブジェクト指向の仕組み」を覚えたのは、実は「オブジェクト指向じゃない言語で」だった(笑)。

「え?上で書いてんのと話が違うじゃん」

とか思うかもしんない(笑)。うん、そうだ。本当だったら「オブジェクト指向言語」でオブジェクト指向を学ぶべきなんだけど、Python弄っててもクラスとかサッパリ使い方が分からんかったんだよな(笑)。
もう、大体予想ついてんだろ?そう、僕が「オブジェクト指向の仕組み」を学んだのはLispで、だ。もっと正確に言うとSchemeで学んだ。しかしSchemeは(狭義の意味では)「オブジェクト指向言語」ではない。
しかし、Schemeでは簡単に「オブジェクト指向っぽい」プログラムを書く事が出来る。
例えばRacketで、銀行口座を作り、口座情報の表示、預け入れ、そして引き出しを行えるメソッドを備えたオブジェクトの「仕組み」は次のように書ける。

(define createBankAccount
 (case-lambda
  ((name pincode balance)
   (lambda (msg)
    (case msg
     ((printBalance) (printf "氏名 : ~a様~%残高 : ~a円~%" name balance))
     ((depositMoney) (lambda (money)
             (set! balance (+ balance money))))
     ((withdrawalMoney) (lambda (pcode reqmoney)
               (when (and (= pcode pincode) (>= balance reqmoney))
                (set! balance (- balance reqmoney))
                reqmoney))))))
  ((name pincode) (createBankAccount name pincode 0))))

Lispを知らない人には、C言語の「構造体のポインタ」が分かりづらいのと同様に「ラムダ塗れやん!」とか思うかもしんない。C言語だろうとLispだろうと、「何かワケの分からん実装」だと。
しかし違うんだ。Lispの場合は「ブレない」。ラムダ式は確かに多用されてはいるが、逆に言うと「ラムダがあれば何でも出来る」と言う、ラムダ式の「応用」の一例なんだ。Lispの場合、「ラムダ一本槍」でどーとでもなる、と言う例であって、「これだけ」ではなく、数多くの「ラムダ式利用の一例」に過ぎない。
もう1つ、Schemeで「オブジェクト指向の仕組みを学ぶ」利点としては、Lisp以外で「ラムダ式を持ってる」プログラミング言語ならどれでも同様の「実装の実験が可能だ」と言う事だ。言い換えると「C言語はラムダ式を持たないので」面倒臭い「枝葉末節にこだわった」実装を行わないとアカン、って「だけ」の話なんだ。


ラムダ式は引数情報等の環境を閉じ込める事が出来る。構造体の出番さえない
上の例を見ても分かるだろうが、「野口英世のアカウント」と「福沢諭吉のアカウント」は重複する事はない。アカウント作成時の環境が閉じ込められてるから、だ。こういうラムダ式の機能をレキシカル・クロージャと呼ぶ。
いずれにせよ、ラムダ式とレキシカル・クロージャの2つの概念のお陰で、僕も「オブジェクト指向とはどういう事なのか」理解する事が出来た。また、上の実装はあくまで「実用的な例」ではなく、やっぱりオブジェクト指向言語が持ってるオブジェクト指向には劣る。しかしながら「基礎のアイディア」、あるいはオブジェクト指向の根幹を学ぶ事は充分可能で、上の実装で「足りない」部分はオブジェクト指向言語でサポートされてるわけだ。
結果僕は、基本を押さえたお陰で、Pythonでclassとか使うのが怖くなくなったわけだ。

なお、上の「オブジェクト指向の仕組み」をPythonで書くと次のようになるだろう。

def createBankAccount(name, pincode, balance = 0):
 def depositMoney(money):
  nonlocal balance
  balance += money
 def withdrawalMoney(pcode, reqmoney):
  nonlocal balance
  if pcode == pincode and balance >= reqmoney: 
   balance -= reqmoney
   return reqmoney
 def dispatch(msg):
  match msg:
   case 'printBalance':
    print(f'氏名 : {name}様\n残高 : {balance}円\n')
   case 'depositMoney':
    return depositMoney
   case 'withdrawalMoney':
    return withdrawalMoney
 return dispatch

Pythonの場合、ラムダ式はあっても機能的には貧弱なんで、クロージャを返すにはローカル関数を設定して、それを「返す」ように書く。
これも関数がファーストクラスオブジェクトで、「ローカル関数がある」言語だと「当たり前の」書き方だが、C言語にはローカル関数もねぇからこんなプログラムも望めない。


Pythonで「オブジェクト指向の仕組み」で書くと、実行形式を見て「ゾッとする」かもしんない。しかし、「関数を返す関数」を書いてる以上、引数を示すタプルを連続して使用する。
これも全然実用的じゃない例だけど、「オブジェクト指向の仕組み」を知るには良い例になってると思う。そして実際、hCard1hCard2と言う「オブジェクト」に対して(文字列で)printBalancedepositMoneywithdrawalMoneyと言うメソッドを「呼び出して」適用している。
マトモにPythonでオブジェクト指向を使うと、上のコードはこうなるが、比較してみて欲しい。ラムダ式を使った「組み立て」を隠蔽してるんだな、ってのが分かるだろう。


実行に関しても、構造は基本的に全く同じだ、って事が分かるだろう。ただ、やっぱり「組み込みで用意されてる」機能の方は、文字列を使って呼び出す、的な面倒な事が無くなってる。
そう、言語のビルトインの機能ってのは、「理論がどうあれ」、面倒臭さを緩和する為に提供されてるわけで、そうでもなければ「✗✗指向言語」と名乗るのはおこがましくなる。反面、「とある機能を理解する」にはその仕組みをメンド臭くても「書く事により」、こうやってその概要を掴む事が出来る。
いずれにせよ、オブジェクト指向を「理解」するにはラムダ式を経由した方が早い。C言語で構造体へのポインタだ何だとクッソ面倒臭いブツを使って実装でワヤクチャになるよか遥かにマシだろう。いや、そうせなアカンのはC言語にはラムダ式が欠けている、とそれだけ、なんだ。

さて、その件のサイト。色々とトンデモが記述されている。非常に香ばしい程のC言語脳だ。
今までもC言語脳を腐してきたんだけど、このブログを読んでる人は実例、っつーか実際どういう考え方をしてるかピンと来ない人も多いんじゃないか、って思う。
しかし、そのサイトの著者はあまりにも典型的なんで、取り上げてみよう。
例えばこんな事を書いてる。



へぇ、メリットかぁ、と。
でもこの3つってそのまま『私は初学者が最初に学ぶ言語として「C言語」を選択することは、次のデメリットからオススメしません。』に転用可能だ。
その3つはマジでそのままデメリットなんだ。



これは上のオブジェクト指向の例を見ても明らかだろう。ミニマムだから概念を掴むのが面倒臭い。ラムダ式もないような言語で一体何の要素を網羅的に学べると言うのか(笑)。
ラムダ式じゃなくてもローカル関数も無い言語ではローカル関数も学べない。一体何をもって網羅的っつってんだかサッパリ分からん。
機能がない、って事は網羅的じゃない、んだよ(笑)。当たり前だろ(苦笑)。



これは「逐次処理」の話をしてるんだけど、そもそも逐次処理って機能はC言語だけのモノじゃない。「逐次処理を学ぶ」為にC言語を学ぶ、ってのは素っ頓狂な論法だ。一体全く何を言ってんだか。っつーか、「下から順番に処理が流れる」プログラミング言語とか、ランダムに処理するプログラミング言語なんざあんのか。

「手続き型言語」は上から順番に処理が流れるため、初心者にはプログラムを作りやすく動きも追いやすい特徴があります。

じゃあBASICでも良くね?って話だ。実は全く「C言語のメリット」でも何でもない。

そのため、手続き型言語の代表である「C言語」こそが最初に攻略すべき言語なのです。

「そのため」もクソもない。論法が飛んでいる。
「C言語じゃなくても」プログラミング言語は上から順番に処理が流れるんで、C言語を最初に学ぶ、って言う主張を補完するモノがここには何もない。
つまり、単に「最初にC言語を学んでほしくて」結論が先にあって書いてる文章だ、ってこった。
騙されるな。



これがまた大嘘だ。オブジェクト指向で「ある」事と、「クラス」と言う形式を採用するのは全く別問題だ。「理論上のモデル」と「実装」を混同してる。



これはこのブログでは何度も「大嘘だ」と指摘している。「C言語を基本として押さえる」とロクな事がない。そして「C言語で学んだ知識は他のプログラミング言語を活用する際には邪魔になる」ってのがホントのトコだ。



これも大嘘だ。事実はC言語はメモリをキチンと抽象化していない、って言った方が正しい。ひっじょーに中途半端に「配列」なぞと抽象化してる。
いや、「メモリ」を正しく理解するのは必要かもしんない。だったらC言語なんて中途半端なツールを使わずにアセンブリや機械語を使うべきだ。そうしたら嫌でもメモリが分かるよ。



これも意味不明だ。
ハッキリ言おう。どんなヤツでもポインタってのは概念的には理解出来るんだよ。Lispやってるヤツでも「ポインタが何か」は概念的には掴めてる。
問題はそこじゃなくって、C言語のポインタ周りの文法がしっちゃかめっちゃかなのが問題なんだ
この人、「C言語 ポインタ完全制覇」を推薦書籍に挙げてるクセに読んでないのか?

 
結局、私自身の経験から言っても、 あるいは初心者がCの学習をするのを見ていても、 私は、以下のことは確信しています。
ポインタが難しいのではない。 C言語の、配列とポインタにかかわる文法が混乱しているだけだ。 

そして、如何にもC言語「しか」ポインタが無いようにミスリードする。詐欺師の手口だわ。
実際は、例えばPascalにもポインタがあって、(Pascalを学んだ事がある)誰も彼もが「Pascalでポインタを学ぶと分かりやすい」と言う。
じゃあC言語である必要無くね?
少なくとも1990年代前半の大学みてぇに、「最初にPascal、2番目にC言語」だったら余計な混乱は起きない、わけだ。
ここでも「最初にC言語と言う結論ありきで」論を展開するからおかしな事になってんだ。
ポインタを学んで利用するにはC言語じゃなきゃいけない、って事はない。要するにこの人の言ってる論を何一つ補完する事実がないんだ。



何言ってんだかサッパリだが(メモリを扱う筋力、って何?)、上に書いた通り。恐らくPascalでポインタを学んだ方が結果良好だろう。
「いきなりC言語でポインタをやるから躓く」だけの話だ。
ポインタと「C言語のポインタ周りの文法のメチャクチャさに慣れる」のは全く関係がない。



また大嘘ばっか書いてる。あくまで「C++」「Java」「C#」に限定した話だろ?
PythonやRubyも「主要な言語」だけど大してC言語の影響なんざ受けてねーよ。

実際に学んでみるとわかりますが、変数定義・型・分岐・反復・関数といった基本的な構文はC言語とほとんど変わりません。

何言ってんの(笑)?殆どの言語で変数定義、型、分岐、反復、関数と言う基本的な構文は「ある」。
って事は別にC言語「じゃなきゃいけない」理由にはなんねーわな。
そして実際は、「C言語を学習した後であれば、新しい言語を身に付ける際に大幅なショートカットが可能と」ならない。むしろ新しい言語の新しい「C言語に無い」概念を学ぶ事を邪魔するだけ、だ。

とまぁ、言ってる事が「結論先にありき」で語ってる為、全く客観性がないんだ。
典型的なC言語脳だ。

んで、いよいよ「香ばしさ」も佳境に入ってくる。



大嘘書いてんじゃねーよ(笑)。
「C言語はC++に内包される」とか、一体いつの時代の話だ(笑)?
既にC++はC言語の上位互換ではない。
うっわぁ・・・何だ、「C言語の仕様を知らない」んじゃねぇの?とか思ったら、やってやがる。




え?どこが間違ってんの?ってコードを二度見した。
間違ってないんだよ。ここに例示されてるコードは何も問題がない。VisualStudioがどーの、とか書いてるけど全く関係がない。正しいコードなんだ。


一応言っておくと、今回使ったのはgccだ。件のコードは問題なく、コンパイル・実行可能だ。
gccだから、ってワケじゃない。標準のC言語コンパイラなら全て同様の結果になる
つまり、

実は、C言語では変数定義が記述できる場所が決まっています。

なんてルールはない、んだ。
つまり、こいつはC言語の仕様書に一回も目を通した事がない、と言うのがここでバレる。そしてC言語の仕様書に一回も目を通した事がないのに、曖昧な事を他人に教えてるワケだな。
ハッキリ言おう。こいつが教えてるのは「C言語に似たナニカ」であって「C言語ではない」。少なくとも2003年に日本産業規格(JIS)で決められた「公式のC言語」を全く知らずに、「違う言語」を「C言語と偽って」教えてきたんだ。

こんな事を書いてるが。



「実際の開発現場で20年の経験を積」みながら一回もC言語の仕様書に目を通した事がない、とはどーゆー事なのか。
そうなると、年間200名を超えてるのは単なる犠牲者だ。
大体、仕様書も読まないような輩が書いたサイトのどこに信頼性があると言うんだ
「学べます、学べます、学べます」と書きながら本人は全く学んでない。少なくともC言語とはどういう言語なのか、その定義が書かれてる仕様書を読まないヤツが何言ったトコで説得力がない。一体何を学んでたんだ。
そして「C言語を知らない」から上のようなバカなポカを書くんだっての。

恐ろしいだろ?C言語脳。
サイトに記述されてる色々とサムいギャグはまぁ許すにしても、堂々と間違った事を書くとか、アタマの中が30年以上前のANSI Cで止まってる、とか、この人が典型的なC言語脳だから取り上げたわけだけど、こういうのがとかく多いんだよ。
う〜ん、だから「教育側」がかなり問題抱えてるよなぁ、ってのが正直なトコだ。学生責める前に教える方が良くない、ってのが特にC言語の場合多すぎるんだよな。マトモな入門書籍もゼロだし。
ホント、だからマジで「プログラミング初心者は最初にC言語は避けた方がいい」。こういう不正確で「仕様書を読んだ事もねぇようなヤツ」からヘンな事を教わるくらいだったら近づかない方がマジでマシだよ。
今回、ホント「C言語脳の酷さ」を見せるには良い例だったとは思う。ある意味反面教師だよな。
  • Xでシェアする
  • Facebookでシェアする
  • はてなブックマークに追加する
  • LINEでシェアする

最近の「プログラミング」カテゴリーもっと見る

最近の記事
バックナンバー
人気記事