オブジェクト指向再考(イントロダクション)

 前回出した記事(オブジェクト指向おじさん?)のあいださんのコメントで最も興味深いものが、オブジェクト指向しかしらないプログラマが増えてきている、というものである。実は私はそれまで『なんでこうオブジェクト指向信者が途絶えないのか?』と疑問に思っていたのだが冷静に考えれば解るとおり『良いも悪いもなくソレしか知らない。』(あいださんのコメント)世代が増えて来ているようだ。幸いにして私の周り半径3メールではそんな奴はいないので私の視野が狭くなっていたらしい。そういう意味では前回の記事をアップして良かったと思う。
また、元々、オブジェクト指向に関する記事を書こうかと思って対象読者を従来の手続き型言語に精通している人としようかと思っていたのだが方針を若干変更してメインターゲットを『オブジェクト指向しか知らない世代』にして、今後増えるであろう、オブジェクト指向症候群に掛かった患者への処方箋を今後数回に分けて書くことにする。
 オブジェクト指向という言葉を聞くとみなさんはどんなイメージをもたれるでしょうか?『オブジェクト指向とは何か?』を素人に説明するとプログラミングパラダイムの事でつまりプログラムを開発する上での一つの考え方や一つの模範ということになる。実はこれ以上でもこれ以下でもないのですが、もしあなたが以下のどれか2つに当てはまるのならオブジェクト指向症候群に掛かっているかもしれないので、この連載は役に立つだろう。

 1.関数という言葉に嫌悪感を感じる。または時代遅れの遺物だと感じる。
 2.よく他のプログラマ・言語に対して『オブジェクト指向ではない』と言っている。
 3.staticを使っている人をみるとプログラマとして終わっていると感じる。
 4.過去にオブジェクト指向を批判した記事を読んだが書いている奴がオブジェクト指向を分かっていないだけだった。
 5.C++が最高、他の言語はダメと思う人。
 6.Javaが最高、他の言語はダメと思う人。
 7.C#が最高、他の言語はダメと思う人。
 8.と言いつつも、自分自身がオブジェクト指向というのが何か実は良く解っていない。

さて、こういうと『お前が解っていないだけだ』と批判を受けそうなので少し私自身について説明します。私は14歳の時からプログラミングを初めて今年で32年目になります。仕事で使った言語は、覚えた順からBasic,Assembly,C,C++,VB,SQL,Java,Perl,PHP,MDX,Ruby,VB.NETです。ちなみにAssemblyは複数のCPUのインストラクションセットを覚えたし、実際に20年前まで仕事で使っていました。メジャーな言語ではC#が抜けているがやったことがないだけです。オブジェクト指向についていうとこれまた20年以上の経験になり、いわゆる手続き型言語からオブジェクト指向言語へコンバートした人になります。批判される前に私のオブジェクト指向の経歴をいうと、十数年前にJavaの記事を書いたこともあるし、ADPというプログラミング言語のプロジェクトを持っているがこれはC++で書かれています。またADPもオブジェクト指向をサポートしてます。その関係で一般のプログラマよりもオブジェクト指向についてよく考えていると自負している。

さて、まず最初の処方箋を言うと、オブジェクト指向は過大評価されている点を挙げましょう。実際は全くそんなことはないのにも関わらず、『オブジェクト指向はプログラマが進む最終地点』と考えている人が多いでしょう。歴史的にみてオブジェクト指向が持てはやされたことがありそれに無意識に乗っかっている人々がいたということもあるが、実はオブジェクト指向自体になにかプログラマを引き付ける魅力があります。ある人はそれを『究極の一手』と表現し、またある人は『彼女(彼氏?)』と言ったり、私自身も『オブジェクト指向はプログラマが進む最終地点』と考えていた時があった。さてここまでで『私がオブジェクト指向を理解していない』と思ったあなたは充分オブジェクト指向病に冒されていますので、何かコメントをしよう考えたのなら少し我慢して以下を読んで頂いて反論を頂きたい。

誰でも知っていることだがオブジェクト指向というのはもともと分類学の技法をプログラミングに取り入れて複雑なプログラムに対応しようというパラダイムの一種で、クラスとか継承とか多態性という言葉は分類学から借りてきたものであるといえる。ここで冷静になって考えてみれば分かることですがそもそも世の中の全ての事柄を分類学でカバーできるでしょうか?世の中の学問を見渡せば分かるとおり分類学では全てはカバーできないことは理解できるでしょう。つまり継承とか多態性というのは一部の領域にのみカバーをすることが保障されているということであり、ここで代表例を挙げると、GUIシステムにはオブジェクト指向がうまく適合できたようで、他の例を挙げると私の経験上になるがプログラミング言語の処理系もうまくマッチすると思う(残念ながら全く問題がない訳ではないが)。その他、経験上言えることは、一連の法則性を持った多様なものを処理するにはオブジェクト指向が向いていると考えられる。ほかの例を挙げると、実はオブジェクト指向ってしっくりこないんです!の記事にある、とりすけ さんのコメントで税金計算処理の適用事例があります。
以上、確かに適用できる事例はありますが、逆にいうと応用例はかなり限定されています。よく自称オブジェクト指向専門家に具体的な話を聞くと『息を吸うようにインタフェースを使っている』という分かったような分からないような返しをされますが、具体的な話ができないということはそもそも彼(彼女)も分かっていないということになるでしょう。本当に息を吸うようにインタフェースを使っているのなら具体例が多数出てくるでしょう。

また、オブジェクト指向の本質はメッセージだ!という人もいらっしゃいます。なるほどメッセージをやり取りすることにより複雑なシステムを簡単に構築しようということらしいです。では以下の2つのコードはどちらが理解しやすいでしょうか?

z = 3 * x * y + 4 * x + 6 * y + 2;

z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);

『下のコードの方が良い』という人はぜひリハビリを行ってください。少なくとも人前では上の方がよいと言いましょう。ちなみに当たり前ですが、これを持ってオブジェクト指向がダメだと言いたい訳ではなく、言いたいことは、『メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする』ということです。
次の回(おそらく来週?)このメッセージについて考察したいと思います。

21件のレスポンス “オブジェクト指向再考(イントロダクション)”へ

  1. tama より:

    >z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);
    演算子とメソッドの区別がない言語もあり例えばScalaでは

    z = 3 * x * y + 4 * x + 6 * y + 2;

    z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);
    と解釈されます。
    つまり上記の批判はメッセージングの批判ではなく演算子とメソッドを区別する言語に向けられるべきでしょう。

  2. ohfuji より:

    tamaさんコメントありがとうございます。

    >演算子とメソッドの区別がない言語もあり例えばScalaでは
    とありますが、ほとんどの言語が演算子のオーバーロードをサポートしており、つまりご指摘の例は他の言語(C#やC++)でも事情は同じです。

    で、本文中では『どちらの記述が理解しやすいか?』という質問であり、区別をする・しないは関係ないです。
    という訳でして本文中の何処をどう読まれて、
    >つまり上記の批判はメッセージングの批判ではなく演算子とメソッドを区別する言語に向けられるべきでしょう。
    と考えられたのか不明です。ので、詳しく説明してください。

    ちなみに、

    >z = 3 * x * y + 4 * x + 6 * y + 2;
    >は
    >z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);

    tamaさんは上か下かどちらの記述が理解しやすいと考えられるでしょうか?

  3. fink より:

    個人的には
    (+ (* 3 x y) (* 4 x) (* 6 y) 2)
    が好きです。

  4. tama より:

    上の方が読みやすいですが
    z = 3 * x * y + 4 * x + 6 * y + 2
    で書けるので問題ないような気がします。

  5. fink より:

    回答ありがとうございます。
    確かに問題はないですね。

    脱線になりますけど
    掛け算がものすごく重たい処理であったとき

    + = 非同期並列評価後に同期加算処理

    と置き換えることで性能出せるとか考えるとこっちも捨てたもんでもないのかな~なんて思ったりしました。

  6. fink より:

    すいません、ohfujiさんからのコメントと勘違いしてました。

    tamaさん

    解釈されようがされまいが、人がソースコード読み書きする際は絶対下の記述
    z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);
    はしないし、コンパイラ、及び処理系がどのように解釈するのか、という点は筆者さんの議論したい内容ではないと思います。

    たとえば、1+x* yという計算を求められたとき、
    ~1はIntクラスのインスタンスオブジェクトだな
    ~Intに加算メソッドは+で用意されてあってIntオブジェクトを返すのか
    ~乗算は*として用意されているから+をループする必要はないな、もちろんIntオブジェクトを返すのね
    ~掛け算は足し算より先に計算しないといけないからかっこを広げなきゃだな
    ~ ということは1.+(x.*(y))で答えが求められる!!!
    という考えにはならないですよね?、小学校の知識で読み書きできる方がみんなハッピーなんじゃない?という論理だと僕は読みました。

    Scalaはマクロ、クラス、トレイト、関数、モナドなんでも込みの変態言語なのでコードゴルフとかで遊んでみると楽しいですよ。

  7. ohfuji より:

    finkさん

    すみません、返信が遅くなりました。tamaさんへの詳しい説明ありがとうございます。今のところ特に補足することはありませんのでtamaさんの返信を待ちたいです。

    >(+ (* 3 x y) (* 4 x) (* 6 y) 2)

    の件ですが確かに脱線しますが実は興味深いです。
    ただ、コメントが混ざりますのでtamaさんの返信を少し待ってみます。
    もっとも勝手な想像ですが、tamaさんはもう返信はされないかと思います。

  8. fink より:

    ohfujiさん

    返信ありがとうございます。差し出がましいことしてしまい、すいません。。

    興味持ってもらってありがたいです。

    tamaさんの返信を待つ件、了解しました。

  9. tama より:

    >z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);
    >はしないし、コンパイラ、及び処理系がどのように解釈するのか、という点は筆者さんの議論したい内容ではないと思います。
    >z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);
    という風にパースするのはコンパイラさんの役目で
    人間は
    z = 3 * x * y + 4 * x + 6 * y + 2;
    と読んでも書いてもいいのです。
    演算子がメソッドであろうとhaskellのように関数であろうとcのように組み込みの演算子であろうと
    わかり難くなったりするものではないと思います、

    >Scalaはマクロ、クラス、トレイト、関数、モナドなんでも込みの変態言語なのでコードゴルフとかで遊んでみると楽しいですよ。
    scalaはflatMapをsyntaxとして特別扱いするだけで型クラスとしてのモナドはないですね
    外部ライブラリを使えば(scalaz,cats等)を使えばできます
    関数についてはFunctionN traitのインスタンスなので機能としてtraitと分ける必要はないかと
    上記に加え他にもHListなんかは変態的で楽しいです

  10. ohfuji より:

    tamaさん

    少し待ちましたが返信がありませんね。
    そもそもの話になりますが、あまりにも説明が少ないので私はtamaさんの主張を理解していません。
    で、私もfinkさんと同様にtamaさんは私の記事を理解できないと認識しています。
    何かあればコメント頂ければと思いますが、最初のコメントはtamaさんの認識違いということでしたらそのまま返信されなくても構いません。がfinkさんへはお礼を言った方がいいかもしれませんね。

    この連載(一か月程休んでいますが・・・)の対象読者は限定されています。読んで解らないのは無理からぬことです。もともとは『オブジェクト指向症候群』にかかった人を対象としていますが、この記事の限界で実践経験がない方には内容は伝わらないかと思います。ただ、実際にオブジェクト指向を使って何か設計をされたことのある方はこの記事の内容は理解できるかと思いますしオブジェクト指向について考え直すきかっけになるかと思います。

    finkさん

    すみません。お待たせしました。

    >(+ (* 3 x y) (* 4 x) (* 6 y) 2)

    を見たときに最初に、『SIMDが使えるな』と思ったのですが、足し算部分で並列処理を起動するという案も確かにありですね。
    現在CPUの進化は『コア数を増やす』という方向に行っていますがこれはプログラマ側から見ればスレッドを使わないと性能が出せないということになります。上記のようなコードを書いた時にコンパイラが裏でスレッドを作ってくれると重宝しますね(まぁ動作予測が難しくなりますが・・・)。将来的にはこういう言語が出てくるかもしれませんね。

    実は私が作っている言語の最適化の方法としてこれに近いことを考えています。数式の最適化ではないのですが、同じように各リストの要素の一つ一つを評価するときにそれらを別スレッドで処理して最後に纏めるというのを考えています。もっとも実装が大変でアイデアで止まったいますが。

  11. tama より:

    コメント返したつもりですが反映されないようです

  12. ohfuji より:

    tamaさん

    失礼しました。6/5のコメントですが、スパム扱いになっていました。

    さて、返信を頂いたのですが、残念ながら解答になっていないですね。

    finkさんのコメント

    >解釈されようがされまいが、人がソースコード読み書きする際は絶対下の記述
    >z = 3.*(x).*(y).+(4.*(x)).+(6.*(x)).+(2);
    >はしないし、

    についてはどう思われるでしょうか?これについてご返信ください。
    なぜ、人は上記の形式でコードを書かないのでしょうか?
    ちなみに、上記のコードは、

    z = 3 * x * y + 4 * x + 6 * y + 2;

    と同じではありません。実はバグが入っています。良く見てください。バグは記事を書いた時に意図的に入れました。バグが一目で解らないところが既に数式をメソッド形式で書くと人が見たときに理解力が落ちることを示しています。

    >演算子がメソッドであろうとhaskellのように関数であろうとcのように組み込みの演算子であろうとわかり難くなったりするものではないと思います、

    ではなぜ、一部のコンパイラは、
    z = 3 * x * y + 4 * x + 6 * y + 2;

    z = 3.*(x).*(y).+(4.*(x)).+(6.*(y)).+(2);
    と解釈するのでしょうか?わかり難くなったりするものではないのなら、下の形式だけで書かせても構わないでしょう。

    繰り返しになりますが、式とメソッドを区別をしないことと以下のコメントの関係をきちんと説明して頂けますか?

    >つまり上記の批判はメッセージングの批判ではなく演算子とメソッドを区別する言語に向けられるべきでしょう。

  13. tama より:

    何かお互いに意思の疎通がうまくいってませんね
    >z = 3.*(x).*(y).+(4.*(x)).+(6.*(y)).+(2);
    こちらは分かり辛く
    >z = 3 * x * y + 4 * x + 6 * y + 2;
    こちらは分りやすいです
    パーサーが
    >z = 3 * x * y + 4 * x + 6 * y + 2;
    をメソッドとして解釈しようがはたまた関数として解釈しようと人間には関係ないのではと思ったまでです。
    >式とメソッドを区別をしないこと
    演算子とメソッドという意図です。
    >つまり上記の批判はメッセージングの批判ではなく演算子とメソッドを区別する言語に向けられるべきでしょう。
    z = 3 * x * y + 4 * x + 6 * y + 2;
    と書ける構文を言語が提供してるならパーサーがどう解釈しようと何か問題があるのかなぁと思った感じです。

    自分の立場を説明しておくと仕事ではscala書いていてオブジェクト指向よりも静的型付け関数型の方が好きですね(scalaはオブジェクト指向ですが) 別にオブジェクト指向サイコーって感じではないです。

  14. fink より:

    tamaさん

    ohujiさんは、
    「数式をオブジェクト同士のメッセージングで処理する言語」(プログラミング言語)
    でもなく、
    「数式で書けばスタックで、メッセージングで書けばヒープで保持演算されるような言語」(プログラミング言語)
    でもなく、
    「全てオブジェクト同士のメッセージングで問題解決を図った方がよいと考えるオブジェクト指向技術者」(人)
    に対しての懸念を示されているのだと思いますよ。

    上記記事を読んでどうして言語への批判と捉えられたのかがよくわからないので説明を求められています。

    そこが噛み合わない限り議論にはならないと思いましたので再度横槍をいれさせていただきました。
    気分を害されたならすいません。

    ofujiさん
    脱線の話題はまた後日記述致します。

  15. tama より:

    >「全てオブジェクト同士のメッセージングで問題解決を図った方がよいと考えるオブジェクト指向技術者」
    なるほど そういう事なら自分が読解ミスだったようです。 どうもです。
    でも
    z = 3 * x * y + 4 * x + 6 * y + 2;

    z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);

    のところが依然としてよく分からないです。。
    「オブジェクト同士のメッセージングで問題解決を図る」としても私なら上のように書けるように設計するからです。(言語が許すなら)

    >気分を害されたならすいません。
    いえいえ こちらこそ米欄汚しすみません

  16. ohfuji より:

    tamaさん

    あなたの疑問に答える前にもう一つ確認させてください。

    『メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする』

    というのがこの記事での私の主張になります。tamaさんはこれに賛成ですか?反対ですか?反対ならその理由を教えてください。

  17. tama より:

    >『メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする』

    メッセージに限らない抽象化含め 同意します。

  18. ohfuji より:

    tamaさん
    ご回答ありがとうございます。

    ここまでのやり取りで解ったことですがtamaさんは私が想定している患者(オブジェクト指向症候群にかかった方)ではないです。そういう意味で私が何を言っているのかわからないかもしれません。

    もっとも、私はまだtamaさんの疑問点について理解していません。というのも数式の扱いは思った以上に複雑で、この連載でも度々数式に触れていてわりと複雑です。
    よろしければ次以降の記事
    http://www.ohfuji.name/?p=2903
    を読んで頂ければ何か見えるものがあるかもしれませんが、ここで少し補足します。ネットの世界ですが、原理主義者と言いますか『 全て オブジェクト同士のメッセージングで問題解決を図った方がよい』という方や、実際の現場では『良いも悪いもなくソレしか知らない。』という方がいらっしゃいます。つまり臨機応変に考えることが出来ない人が居るということです。

    z = 3 * x * y + 4 * x + 6 * y + 2;

    z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);

    この2つの記述ですが、上の形式は数学からのもので、下の形式はオブジェクト指向からのものです。もし、「 全て オブジェクト同士のメッセージングで問題解決を図った方がよい」と考える方が、上の形式を選択するとすればそこには矛盾がありますよね? つまり、全てをメッセージでプログラム組むことは実務的ではないということが言いたい訳です。
    数式というと、あまりにも当たり前に使っているので、数式をオブジェクト指向で組む必要性が出てくるとは思われないかもしれません。が、厳密に言えば、上の形式でプログラム組むことはオブジェクト指向に反することになります。
    この矛盾は原理主義者にとっては泣き所になります。もし身近に原理主義者の方がいれば、この点を指摘してみてください。どういう返答がくるか興味があります。

    さて、話がここで終わらないのがとても厄介なところです。例えば上の数式に対して、

    x,yは浮動小数点数として定義されていますが、全てを一旦整数型に変換した上で計算を行う。

    という条件を加えたとしましょう。とすると上の数式は、

    z = 3 * int(x) * int(y) + 4 * int(x) + 6 * int(y) + 2;・・・・(A)

    という風に変換できるかもしれませんが、一部メッセージの考えを取り入れますと、

    z = 3 * x.int * y.int + 4 * x.int + 6 * y.int + 2;・・・・(B)

    と記述することも出来るでしょう。tamaさんは(A)と(B)どちらが読みやすいと思われますか?
    (A)の方もありだとは思います。が、私個人は(B)の方が読みやすいと考えます。

    つまり、
    『メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする』
    という注意書きの背景として、使える道具は積極的に使いましょうということがあります。

    最後になりますが、『このような議論に何の意味があるのか?』と疑問に思われるかもしれません。この手の議論はプログラマとしての知見を高める訓練となりますね。たとえば、我々がどこかで、

    z = 3.multiply(x).multiply(y).add(4.multiply(x)).add(6.multiply(x)).add(2);

    というコードを見た場合、少なくとも『あーこの人はオブジェクト指向を支持している人だな』と思うことができます。

    何でこんなコードを書くんだ?→こいつは下手な奴

    という早合点をしなくて済みます。

  19. ohfuji より:

    tamaさん
    4日程経ちましたが返信がありませんね。せめて疑問点について解消されたのかどうかを教えて頂けるとありがたいのですが。
    何れにしても、このまま何も返信がなく、いたずらにコメント欄を汚したことになってしまうのもどうかと思うのですがね。
    私は結局あなたが何が言いたいのか理解できずじまいになりますね。

  20. fink より:

    ohfujiさん

    tamaさんのお返事が内容なので脱線の件追記致します。

    まずは、脱線にもかかわらず丁寧なご回答ありがとうございます。

    >現在CPUの進化は『コア数を増やす』という方向に行っていますがこれはプログラマ側から見ればスレッドを使わないと性能が出せない
    これについて私もいろいろ考えていまして、平行処理できそうなところはコンパイラが勝手にやってくれれば便利ですよね。

    >(まぁ動作予測が難しくなりますが・・・)
    とおっしゃられているように副作用が絡むような場合は無理ですし、変数のブロックの考慮とか考えたくもない、というのも現実問題としてあります。

    私現在が並列処理を実装する際の道具として実はScalaを使っていまして、
    当稿の例を実装するとしたら(便宜的にzはxとyを取る関数としています)
    val z = (x: Int, y: Int) => List(()=>3*x*y, ()=>4*x, ()=>6*y, ()=>2).par.map(_()).fold(0)(_+_)
    このようなコードになります。
    「(…) => … 」はラムダ式で()内がパラメータリスト、右辺が評価式になります。
    List(…)の後のparがポイントでこれを宣言することでリスト内を並列走査してくれるようになります(同時実行数は処理系のコア数に準ずる)。
    map(_())はmap((f)=> f())の簡略記述形式でして、par.map(_())とすることでSeq内の関数をコア数に応じて並列に評価しろ、という宣言になります。
    foldは畳み込み演算でこちらも並列処理されます。略さず書くとfold(0)((acc, n) => acc + n)でこの例で行くと
    前述のmapで導き出された結果
    v1 = 3*x*y
    v2 = 4*x
    v3 = 6*y
    v4 = 2
    を第一引数に渡された初期値に対し並列処理で畳み込みます。
    順不定ですが、
    1段目
    v5 = 0 + v1
    v6 = 0 + v2
    v7 = 0 + v3
    v8 = 0 + v4
    2段目(下記v5,v6,v7,v8はどこに入るか不定)
    v8 = v5 + v6
    v9 = v7 + v8
    3段目
    v10 = v8 = v9
    となり走査が終わったv10が最終的な結果となります。
    ※合算に限るとsumという便利メソッドがありますが今回は省きます。

    x, yの共用が気持ち悪いのでこれを排除する場合は
    case class Context(val x:Int, val y: Int)
    val z = (ctx: Context) => List[Context => Int](
    c => 3*c.x*c.y,
    c => 4*c.x,
    c => 6*c.y,
    c => 2
    ).par.map(_(ctx)).fold(0)(_+_)
    このような実装になります。

    さらに行くとAkkaという製品が秀逸で、マルチスレッドに加えて複数サーバーでの並列実行も簡潔な記述で可能にしてくれますが長くなりすぎるので今回は割愛します。

    以上、メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする例でした(悪乗り申し訳ないです)。

    >実は私が作っている言語の最適化の方法としてこれに近いことを考えています。
    言語実装されているとのこと、軽くではありますが拝見しました。
    深くコメントできるまで至っていませんが、コンセプト(思想)は興味深いです。
    マルチスレッド対応、期待しています。

  21. ohfuji より:

    finkさん
    すみません。スパムに入っていまして気が付きませんでした。

    Scalaではパラレルイテレータというのですね。先行して実装している例をみるとちょっと触発されますね。ちなみにfoldの考え方は目から鱗ですね。

    >以上、メッセージというある種のプログラムを抽象化する道具も乱用すると却って悪戯にプログラムを複雑にする例でした(悪乗り申し訳ないです)。

    なかなか秀逸なコメントなので座布団一枚というところで、このまま返信はしないでおこうかと思いましたが、悪乗りついでにコメントを加えます。

    リスト形式は、確かに『数式の抽象化』においてはプログラムを複雑にする例となるかもしれませんが、『並列処理の抽象化』と考えればよい例かと思います。私は初期のオブジェクト指向言語にスレッドクラスというものが搭載されたのを見たときに『やりたいことは並列処理であってスレッドの起動ではないだろう』と落胆したものですが、パラレルイテレータのようなものを見ると時代は進んでいると実感できますね。

    良い例をありがとうございます。励みに頑張ります。

コメントを残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です