『コンピュータ・システム プログラマの視点から』で知識の糸を織りあげる

『コンピュータ・システム プログラマの視点から』 はコンピュータ・サイエンスの教科書です. コードを書いて, コンパイルして, プログラムを実行する一連の流れにおいて, コンピュータの中では実際のところ何が起きているのかを知りたい人のための本です. 扱う範囲が幅広く CPU アーキテクチャ メモリ階層 リンクの仕組み 仮想メモリ 並行プログラミング など, 盛り沢山な内容となっています. 非常に分厚い本で 900 ページ近くあるのですが, これでも内容は絞られています. 副題の「プログラマの視点から」というのは大事な指針です. 多岐に渡る本書の内容は, どれも「C 言語を書くときに知っておいたほうが良いかどうか」という基準で取捨選択されています. 例えばアセンブラを学びますが, アセンブラを自力で書けるようになることは目的としていません. そうではなく, コンパイラが出力したアセンブラを読んで挙動を追ったり性能を最適化したりすることができるようになることが目的です. ほぼ全てのものが順を追って説明されるので前提となる知識は少ないです (大学のコンピュータ・サイエンス入門コースを元にした本らしい). 例えば CPU のパイプライン制御の章では「論理ゲートとは」というところから話が始まります. 個人的には, これまで学んできたことが関連付けられたり補強されたり, 知識や理解を整理する良い機会となりました. 以下印象に残った点をかいつまんでまとめます. 浮動小数点 浮動小数点はなんとなく地味な存在だと思っていて, これまであまり深く考えたことがなかったのですが, 今更ながらよく考えられたフォーマットだなと思いました. 昇順に並べた時ビットが符号なし整数と同じになる, 非正規化数から最小の正規化数まで等間隔に滑らかにつながると言う事実を知って驚きました. かつては仕様が乱立していた時代もあったそうですが, 今の形に落ち着いたのも納得です. 実用的には小数と整数の変換で誤差が出るかどうか, 丸めがどのように行われるのかといったことは把握しておくと役に立つかもしれないと思いました. アセンブリ C 言語がどのようにアセンブリに変換されるのかが説明されています. 例えば if は条件ジャンプを使って実現されることをなどを学びます. このあたりは昔 『コンピュータシステムの理論と実装』で自力で考えたことがありました が, 本書を先に読んでいれば楽だったかもしれないと思いました. 多くは既知の内容でしたが, switch については認識を改めました. これまで if-else と同じようなものだろうと思っていたのですが, アセンブリのレベルで見ると実装方法が異なります. switch はジャンプテーブルを用いて対象の case に直接ジャンプするので効率が良いです. if-else の連続だとその回数分条件式が評価されますしね. switch の case には定数しか書けないというような制約があったりして疑問に思っていたのですが, アセンブリを知れば納得です. ...

August 14, 2022 · 2 min

『ふつうの Linux プログラミング』で 3 本の柱をものにする

『ふつうの Linux プログラミング』で 3 本の柱をものにする 『ふつうの Linux プログラミング』 は Linux での C 言語プログラミング入門書です. 3 つのコンセプトを軸に据えた説明が特徴で, すんなり読めて自然に Linux の勘所が分かるような構成です. 3 つのコンセプトとは ストリーム ファイルシステム プロセス のことです. これらを中心に据えて Linux の仕組みを学びます. タイトルにある「ふつうの」は標準的な方法を学ぶという意図を表しています. Linux の中心的な仕組みを知ることができるだけでなく, cat や grep など身近なコマンドを実装するなどの実例も豊富なので, 「API は分かったけど結局どう使うのか分からない」といったことがありません. 実践しながら Linux の仕組みを学びたい方におすすめです. 3 つのコンセプト まずは 3 つのコンセプトについての説明です. データを保存する場所である「ファイルシステム」 コンピュータ上での活動の主体である「プロセス」 プロセスがファイルや他のプロセスとデータをやり取りするための「ストリーム」 ストリームは本書独自の用語のようですが, バイト列の流れのことです. この 3 つのコンセプトが念頭にあれば Linux の様々なものを整理して理解することができます. 以下のような説明してみます. リダイレクト: プロセスの標準入出力ストリームの先をファイルに変える機能 パイプ: プロセスとプロセスを繋ぐストリーム シグナル: カーネルからプロセスへのストリーム (のようなもの) パーミッション: プロセスからファイルへのアクセスを制限する仕組み 確かに Linux についての多くのものが整然と理解できる気がするので, この 3 つのコンセプトに着目して Linux を学ぶのは優れたアプローチだと思いました. ...

July 24, 2022 · 2 min

『Effective C#』で C# に親しむ

様々な言語にある Effective シリーズの C# 版 『Effective C# 6.0/7.0』 です. 基本的な文法の説明などはなく, 実践的な問題に対するテクニックやアプローチの仕方が 50 項目掲載されています. C# の基本的なことは分かったという状態で読むと理解が深まるでしょう. 50 項目のうち特に印象に残ったものを紹介します. 項目 2 const よりも readonly を使用すること 混乱しがちな const と readonly についての項目です. 両者の最も大きな違いは, const はコンパイル時, readonly は実行時に解決されるという点です. コンパイル時定数の const 変数は, コード中の使用箇所をその値で置き換えたような IL が生成されます. この仕組みによって const 変数が別アセンブリで参照される場合, 気づきにくいバグを生む可能性があります. const 変数の値を変更したとしても, その変数を使用しているアセンブリではリビルドするまで変更前の値のままになるのです. よって基本的にこの問題を回避できる readonly を使ったほうがよいという主張です. しかし, これは const 変数を外部のアセンブリに公開した場合のみに起こる現象なので, private や internal にしておけば済む話です. ライブラリではないプログラムの場合はそもそも外部のアセンブリに使われることがないので関係ありません. よってスローガンは「外部アセンブリに公開する変数は const よりも readonly を使用すること」の方がより正確だと思います. もちろん const にはパフォーマンスの利点しかないので, 柔軟性を重視して常に readonly を使うという考え方もありかもしれません. しかし, コンパイル時に決まる値ならコンパイル時に決めたほうが良いですし, デメリットを理解した上で const と readonly を適切に使い分けるべきということですね. ...

July 10, 2022 · 5 min

『SQL パズル』は楽しさと実用を兼ねた SQL 例題集

『SQL パズル 第 2 版 プログラミングが変わる書き方/考え方』 は SQL 問題集です. 収録数 75 問という圧巻の豊富さです. 具体的で実用的な題材によって, 問題へのアプローチの仕方や SQL の奥深さを知ることができます. タイトルには「パズル」とありますが, 本書は決してパズルのためのパズル本ではありません. あくまでも実用的な SQL を学ぶことを目的としているので, 実務にも大いに役立つでしょう. 一部まさにパズル的な問題もありますが, それは SQL の幅広さを知る小休止的なものだと思いました. 本書を読まれる方には副読本として 訳者ミックさんのサポートベージ をおすすめします. 以下印象に残った問題をいくつか紹介します. パズル 1 「会計年度テーブル」 会計年度を持つ以下のようなテーブルがあります. 1 2 3 4 5 CREATE TABLE FiscalYears ( fiscal_year INTEGER, start_date DATE, end_date DATE ); このテーブルは, 各会計年度がいつ始まっていつ終わるのかを格納します. 会計年度は 10/1 から 9/30 までのアメリカ方式とします. 例えば以下のようなデータが入っています. ...

May 18, 2022 · 9 min

『C# による マルチコアのための非同期/並列処理プログラミング』で C# の非同期を概観する

本書はタイトルの通り C# の非同期/並列処理についての書籍です. 対象としているのはマルチスレッドの理論的な事柄ではありません. .NET や C# にすでに備わっている環境をどのように利用してプログラムを書くかということに焦点を当てています. そのため, 具体的な.NET のライブラリの使い方を, 実践を通じて知りたい方におすすめです. 個人的な白眉は昔のバージョンから新しいバージョンまで, 各 .NET での実装が比較されている点です. バージョン 1.x 系の.NET ではこう書く, 2.x 系ではこう書く, といった風にして, 1.x 系から 4.5 まで扱います. 今更昔のバージョンの .NET を利用することはないとはいえ, 歴史的な変遷を見られてためになりました. 昔はこんなに面倒だったのかと驚き, それによって新しいバージョンでの書き方では何が省略されているのかイメージを掴むことができました. 非同期/並列処理の基礎 まずは非同期/並列処理とは何か, ということから始まります. マルチスレッド, レースコンディション, ロック, スレッド間同期といった主要なトピックスが紹介されています. この辺りのことはすでに一通り知っていたので新鮮さはなかったのですが, 同じことでも別の説明を読むのはためになります. いいなと思ったのは「非同期」と「並列」という言葉の使い分けです. 「並行」と「並列」が一般的ですが, これらは混同しやすいので本書では並行の代わりに非同期という言葉が使われています. 個人的にも「並行」と「並列」は言葉だけだといつも分からなくなるので「concurrent」と「parallel」で覚えていますが, 「非同期」と「並列」の方が分かりやすくて良いかもしれません. 新旧 .NET で変遷を見る 例題を各バージョンの .NET で実装して違いを見る章があります. 例題は「1-10 の数字を 3 桁に 0 埋めして画面に表示する」です. マルチスレッドで並列に計算することと, 画面をフリーズさせないように計算を非同期で行うという 2 つ問題を含んだ題材です. これを最初に見たとき, なぜこんな簡単なものが例題になりうるのだろうと思いました. 計算はAsParallel()を使って簡単に実装できます. 1 2 3 4 Enumerable.Range(1, 10) .AsParallel() .Select(x => x.ToString("000")) .ForAll(s => Console.WriteLine($"{s} ({Thread.CurrentThread.ManagedThreadId})")); 出力を見ると, ちゃんと複数スレッドで順不同に実行されていることが確認できます. ...

April 18, 2022 · 2 min

キャリア 2 年目の終わり

社会人生活を始めてから 2 年が経過した. この 1 年の振り返りと次の 1 年の目標を整理する. 2 年目の振り返り チームに約 2 年いて, 自分が果たすべき役割がかなりはっきりしてきた. 作っているアプリに対して, 自分がやるべきこと, やれること, 今後どうなっていくのかということが見えてきた. また, 最初はアプリやソースコードの規模に圧倒されていたが, ようやく全体を把握できつつある. もちろんあらゆる細部までを把握したわけではないが, 主要なところは一通り抑えたという感覚がある. 仕事をしていて意外だったのは, 案外ベテランでも知らないことはあるということ. 凄い人は何でも知っていそうに見えるが, 本当になんでも知っているわけではない (当たり前だが). 経験の浅い自分でも, 特定の分野に限って言えば凄い人の劣化版としてではなく一人前の活躍ができるという手応えが得られた. この経験の影響で, 一つに分野に集中して知識を深めることや, 他の人がカバーしてないマイナーな分野に力を入れることが有用であるという考えが形成されてきた気がする. プライベートの時間でも技術書を読んで勉強を続けてきた. メインテーマはコンピュータ・サイエンスを幅広く学び基礎を固めるということだった. どういった分野を学ぶか, どういった本を読むかを決めるため Teach Youself Computer Science というサイトを主に参考にした. このサイトによると, コンピュータ・サイエンスは大きく 9 つの領域に分けることができる. プログラミング コンピュータアーキテクチャ アルゴリズムとデータ構造 数学 OS ネットワーク データベース コンパイラ 分散システム それぞれの内容やおすすめの書籍, サイトなどが紹介されていて, とても分かりやすかったので勉強の指針とさせてもらっている. この分類だと, この一年は主にプログラミング, コンピュータアーキテクチャ, コンパイラ辺りを学んだ. ずっと重厚な本を読んでいると疲れてきて直接の関係はない本も読んだが, 中でも関数型言語に触れられたのは良かった. 結構好みかもしれないと思っている. どの書籍からも学ぶことが多く, 自分が如何にものを知らないか痛感する思いだった. まともな知識がないと考えることができないので, 知識があってようやくスタートラインに立てるということは日々実感している. 本当は学生時代に真面目に勉強していればこういった基礎が一通り身についていたのかもしれないが, 後悔しても仕方ないので地道に勉強を続けるしかない. まあ学生の頃に「Effective C++」を読んでもほとんど頭に入ってこなかっただろうと思うので, 経験を積むのが必要なことだったのかもしれない. ...

April 11, 2022 · 1 min

『並行プログラミング入門』で並行処理のトピックスを網羅する

本書は並行プログラミングに関する様々なトピックを紹介する本です (『並行プログラミング入門 ――Rust, C, アセンブリによる実装からのアプローチ』). 副題にもある通り, アルゴリズムを C やアセンブリで低レベルに実装して, Rust で高レベルに使うというような流れです. 実践的な何かを作るというより, 仕組みを理解することに重点が置かれた本で, タイトルの通り並行プログラミングに入門したい方におすすめです. キーワードの一部 レースコンディション デッドロック async/await マルチタスク アクターモデル λ計算, π計算 並行して実行されてはいけない処理 並行プログラミングを考える上で注意を払わなければならないのは, 複数のプロセスで同時に実行されてはいけない箇所の扱いです. 複数プロセスで実行されてはいけないということは, 実行中を表すフラグを管理しておけばよいのではないかと思うわけですが, 以下のコードで問題はないでしょうか. 1 2 3 4 5 6 7 8 9 10 11 12 13 bool is_in_progress = false; void f() { // Wait while other process is in progress. while (is_in_progress) {} is_in_progress = true; // Must not be executed concurrently. do_something(); is_in_progress = false; } 一見すると問題ないように思えます. しかし, 並列処理においては do_something() が複数同時に実行される可能性があります. なぜかというと, あるプロセスでis_in_progressが false になり while を抜けて true を代入するまでの間に, 他のプロセスでもis_in_progressが false となっているからです. ...

March 20, 2022 · 3 min

『達人に学ぶ SQL 徹底指南書』で SQL の可能性を知る

本書は SQL 初心者から中級者への架け橋となる本です (達人に学ぶ SQL 徹底指南書 第 2 版 初級者で終わりたくないあなたへ (翔泳社)). 本書の目玉となる case 式やウィンドウ関数を始めとした便利な道具を使いこなすための説明 + 練習問題に加え, SQL の理論的なバックグラウンドや歴史的経緯にも触れて, SQL がなぜそうなっているのかの疑問にも答えます (なぜループや変数がないのか, なぜ NULL 関係の動作が非直感的で複雑なのかなど). 基本的な構文は一通り分かったけど, 更に脱初心者を目指して学びを深めたい方におすすめです. 本記事では本書で挙げられた便利な道具について触れていきます. case 式 case 式は条件分岐を記述するための構文です. 1 2 3 4 CASE WHEN [predicate] THEN [value] WHEN [predicate] THEN [value] ELSE [value] END 例を見ると分かりやすいです. テスト用にテーブルを作ります. ヤギのデータです. 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 create table goats ( id int PRIMARY KEY, weight INT UNSIGNED, birthday DATE, color VARCHAR(1), name VARCHAR(10)); insert into goats values(1, 63, '2016-03-02', 'W', 'Alice'); insert into goats values(2, 79, '2012-06-25', 'W', 'Bob'); insert into goats values(3, 76, '2020-02-01', 'W', 'Carl'); insert into goats values(4, 75, '2022-11-27', 'W', 'Dan'); insert into goats values(5, 70, '2014-08-29', 'B', 'Elie'); insert into goats values(6, 69, '2013-06-07', 'B', 'Fai'); insert into goats values(7, 67, '2013-01-16', 'B', 'Gabi'); insert into goats values(8, 63, '2014-05-14', 'B', 'Helen'); 1 2 3 4 5 6 7 8 9 10 11 12 13 select * from goats; +----+--------+------------+-------+-------+ | id | weight | birthday | color | name | +----+--------+------------+-------+-------+ | 1 | 63 | 2016-03-02 | W | Alice | | 2 | 79 | 2012-06-25 | W | Bob | | 3 | 76 | 2020-02-01 | W | Carl | | 4 | 75 | 2022-11-27 | W | Dan | | 5 | 70 | 2014-08-29 | B | Elie | | 6 | 69 | 2013-06-07 | B | Fai | | 7 | 67 | 2013-01-16 | B | Gabi | | 8 | 63 | 2014-05-14 | B | Helen | +----+--------+------------+-------+-------+ ヤギの体重が基準値に収まっているかどうかを調べることを考えます. 以下の基準を満たしている場合は ‘OK’, 満たしていない場合は ‘NG’ と表示することにします. ...

March 12, 2022 · 10 min

『プロを目指す人のための Ruby 入門』は丁寧で網羅的な入門書

始めに 誕生から 25 年以上経って, 今更ですが Ruby に入門しました. 本書は Ruby の重要なトピックスを網羅するのみならず, 開発の現場で役に立つようなテクニックの説明にも力を入れられています. Ruby をなんとなく知っているが改めてきちんと学びたい方や, 私のように他言語での経験はあるが Ruby は未経験という方におすすめです. 親切な説明のおかげですらすら読めましたし, 静的型付け言語に親しんできた身からすると新鮮な驚きが多数あったので非常に楽しめました. 3 行でまとめ 丁寧な説明で読みやすい 静的型付け言語に親しんできた身からすると新鮮な驚きが多数あった 便利なスクリプト言語として使っていきたい あらゆるものがオブジェクト すべてがオブジェクト (「Ruby コミュニティサイト: Ruby とは」より) 「すべて」の中には例えばリテラルも含まれます. 数値や文字列のリテラルもオブジェクトなので, メソッド呼び出しが可能です. 1 2 3 "hello".upcase # => HELLO 5.times { puts "hello" } [1, 2, 3].map { |n| n ** 2 } # => [1, 4, 9] ついでに, 範囲型や正規表現もリテラルとしてサポートされています. 1 2 3 4 (1..10).include?(4.5) # => true /[a-z]\d+/.class # => Regexp "a123-4e56-789".scan(/[a-z]\d+/) # => ["a123", "e56"] さらに, クラスやモジュール自体もオブジェクトです. ...

February 12, 2022 · 3 min

『Go 言語でつくるインタプリタ』を OCaml でやる

導入 出版社のページ 実際にインタプリタを作りながら, インタプリタの仕組みを学ぶ本です. インタプリタを作るというのは, 例えば以下のようなものを作るということです. 1 2 3 4 5 6 7 8 9 10 11 12 >> -5 + 1 -4 >> (1 < 2) == !true false >> if (1 < 2) { 10 } else { 20 } 10 >> let add = fn (x, y) { x + y; } >> add (1 + 2, 3) 6 >> let fact = fn(n) { if (n == 0) { 1 } else { n * fact (n - 1) }}; >> fact(5) 120 以下のような方におすすめです. ...

February 6, 2022 · 4 min