目次
- はじめに
- 謝辞
- 本書の構成
- サンプルコードのダウンロード
第1章 言語を深く効率的に学ぶには
1.1 比較から学ぶ
- 決め事は言語によって異なる
- C言語とRubyにおける真偽値
- Javaにおける真偽値
1.2 歴史から学ぶ
- 言語設計者の意図を理解する
- どの言語を学ぶべきかは誰にもわからない
- 言語に依存しない普遍的な知識を学ぶ
1.3 まとめ
第2章 プログラミング言語を俯瞰する
2.1 プログラミング言語誕生の歴史
- ケーブルをつなぐ
- プログラム内蔵方式へ
- FORTRANの登場
2.2 プログラミング言語の生まれた目的
- 無精 ──プログラマの三大美徳の一つ
- 言語により異なる「楽さ」の意味
- 何を楽にしたいのか
- どんなプログラムを書くのを楽にしたいのか
2.3 まとめ
第3章 文法の誕生
3.1 文法って何だろう?
- 演算子の優先順位
- 文法は言語設計者が決めたルール
3.2 スタックマシンとFORTH
- 計算の流れ
- 計算順序をどう表現する?
- 現代にも生きるスタックマシン
3.3 構文木とLISP
- 計算の流れ
- 計算順序をどう表現する?
- 現代にも生きる構文木
- 【Column】理解を確認するためにはまずアウトプット
3.4 中置記法
- 構文解析器
- 【Column】何を学べがよいかがわからない理由
- ルールの競合
3.5 まとめ
第4章 処理の流れのコントロール
4.1 構造化プログラミングの誕生
4.2 ifが生まれる前
- ifはなぜあるのか
- if……elseはなぜあるのか
- アセンブリ言語での表現方法
- C言語での表現方法
- if……elseを使うメリット
4.3 while ──繰り返しのifを読みやすく表現
- whileを使った表現方法
- whileを使わない表現方法
4.4 for ──数値を増やしながらのwhileを読みやすく表現
- forを使った表現方法
- forを使わない表現方法
- foreach ──処理の対象で繰り返しを制御
4.5 まとめ
第5章 関数
5.1 関数の役割
- 理解 ──組織のたとえ
- 再利用 ──部品のたとえ
- プログラムにおける再利用の特徴
5.2 戻る命令
- 関数の誕生
- 戻る先を記録する専用のメモリ
- 【Column】名前
- スタック
5.3 再帰呼び出し
- 入れ子構造のデータを効率的に処理
- 入れ子構造を扱う方法
- forでは表現できない
- 再帰呼び出しを使う
- 再帰呼び出しの実行の流れ
5.4 まとめ
第6章 エラー処理
6.1 プログラムも失敗をする
6.2 失敗をどうやって伝える?
- 返り値で失敗を伝える
- 失敗を見落とす
- エラー処理のせいでコードが読みづらい
- ジャンプでエラー処理をまとめる
- 失敗したらジャンプする
- UNIVAC Iの場合
- COBOLの場合
- PL/Iの場合
6.3 失敗しそうなコードを囲む構文
- John Goodenoughの主張
- CLUへの導入
- C++への導入
- Windows NT 3.1への導入
6.4 出口を1つにしたい
- なぜfinallyを導入したのか
- 対になる処理を確実に行いたい
- finallyによる解決
- finallyのないC++での解決
- D言語のscope(exit)による解決
6.5 どういうときに例外を投げるか
- 関数呼び出し時に引数が不足している場合
- 配列の範囲外を取得しようとした場合
- 間違えたらすぐに例外を投げてほしい
6.6 例外の伝搬
- 例外が伝搬する問題点
- Javaの検査例外
- 検査例外が普及しない理由
- 【Column】具体的な知識と抽象的な知識
- 【Column】噛み砕く
6.7 まとめ
- 【Column】必要なところからかじる
第7章 名前とスコープ
7.1 名前はなぜ必要だったか
- どうやって名前を付けるか
- 名前の衝突
- 衝突を回避するには
- 長い変数名を付ける
- スコープを利用する
7.2 スコープの進化
- 動的スコープ
- どのように動作するか
- 問題点
- 静的スコープ
- 動的スコープは対応表がコード全体から読める
- 静的スコープは関数ごとに対応表を分ける
7.3 静的スコープは完成形?
- 【Column】ほかの言語でのスコープは?
- ネストした関数の問題
- 外のスコープへの再束縛の問題
- Pythonでの解決方法
- Rubyでの解決方法
7.4 まとめ
第8章 型
8.1 型とは何か
8.2 数値をオンとオフで表現する方法
- 位取りの発明
- 7セグメントディスプレイ
- そろばん
8.3 1つの位に必要なランプはいくつか?
- 10進法から2進法ヘ
- 8進法と16進法
- 8進法
- 16進法
8.4 実数はどうやって表現しよう
- 固定小数点数──小数点がどこに付くか決める
- 浮動小数点数──どこからが小数部かの情報自体を値に含める
- どのような考え方か
- IEEE 754で定められた浮動小数点数のしくみ
- 問題点
8.5 型は何のため?
- ないとどう困るのか
- 初期のFORTRANでの型
- 言語処理系に変数の種類を教える
- 暗黙の型昇格
- 整数同士,浮動小数点数同士の演算
- 片方が整数で片方が浮動小数点数の演算
- 問題点
- 書き方で区別する言語
8.6 型のいろいろな展開
- ユーザ定義型とオブジェクト指向
- 仕様としての型
- 公開と非公開を分ける
- インタフェースへの発展
- 型ですべての仕様を表現する世界が来るか
- 総称型,ジェネリクス,テンプレート
- C++の場合
- Javaの場合
- Haskellの場合
- 動的型付け
- どのように実現しているか
- メリットとデメリット
- 型推論
- Haskellと型推論のないC言語の比較
- Haskellの型推論
- Scalaの型推論
- 強い型でバグのないプログラムが作れるか
8.7 まとめ
- 【Column】おおまかにつかんで徐々に詳細化する
第9章 コンテナと文字列
9.1 いろいろな種類のコンテナがある
9.2 なぜいろいろな種類のコンテナがあるのか
- 配列と連結リスト
- 配列に値を挿入する場合
- 連結リストに値を挿入する場合
- 連結リストの模式図
- 連結リストの長所と短所
- 【Column】O記法──計算時間とデータ量の関係を簡潔に表す
- 言語による違い
9.3 辞書,ハッシュ,連想配列
- ハッシュテーブル
- 木
- 要素を取り出す時間
- 木の場合
- ハッシュテーブルの場合
- 万能のコンテナはない
9.4 文字とは何か
- 文字集合と文字符号化方式
- コンピュータ以前の符号化
- モールス符号
- ボーコード
- EDSACの文字コード
- ASCIIとEBCDICの時代
- 日本語エンコーディング
- ISO-2022-JP
- Shift_JIS
- EUC-JP
- Shift_JISがプログラムを壊す
- マジックコメント
- Unicodeによる統一
9.5 文字列とは何か
- 長さの情報を持つPascal文字列,持たないC文字列
- NUL文字で文字列の終わりを表現する
- NUL文字にまつわる不具合の例
- 1文字16bitのJava文字列
- Python 3で行われた設計の変更
- Ruby 1.9の挑戦
9.6 まとめ
第10章 並行処理
10.1 並行処理とは何か
10.2 細かく区切って実行する
10.3 処理を切り替える2通りの方法
- 協調的マルチタスク──切りの良いところで交代する
- プリエンプティブマルチタスク── 一定時間で交代する
10.4 競合状態を防ぐには
- 競合状態の3条件
- 共有しない──プロセスとアクターモデル
- プロセスではメモリを共有しない
- 共有しないアプローチは成功したか
- アクターモデル
- 書き換えない──const,val,Immutable
- 割り込まない
- 協調的なスレッドを使う──ファイバー,コルーチン,グリーンスレッド
- 割り込まれると困る処理中は印を付ける──ロック,ミューテックス,セマフォ
10.5 ロックの問題点と解決策
- ロックの問題点
- デッドロックが発生してしまう
- 合成できない
- トランザクショナルメモリによる解決
- トランザクショナルメモリの歴史
- ハードウェアによる実装
- ソフトウェアによる実装
- トランザクショナルメモリは成功するか
10.6 まとめ
第11章 オブジェクトとクラス
11.1 オブジェクト指向とは何か
- 言語によって違う「オブジェクト指向」の意味
- オブジェクトは現実世界の模型
- クラスとは
11.2 変数と関数を束ねて模型を作る方法
11.3 方法1 モジュール,パッケージ
- モジュール,パッケージとは何か
- Perlのパッケージでオブジェクトを作る
- モジュールだけでは足りない
- データ置き場は個別に
- 引数に個別のハッシュを渡す
- 初期化の処理もパッケージに入れる
- ハッシュとパッケージを結び付ける
- ファーストクラス
- 関数をハッシュに入れる
- 複数のカウンタを作る
- 共有してよいモノをプロトタイプに移す
- プロトタイプの動作
- new演算子で効率的に記述する
- これがオブジェクト指向?
- クロージャとは
- なぜクロージャと呼ぶ?
- Hoareの考えたクラス
- C++のクラス
- 仕様としての役割
- クラスが持つ3つの役割
- 継承に対するさまざまな考え方
- 一般化/特殊化
- 共通部分の抽出
- 差分実装
- 継承は諸刃の剣
- リスコフの置換原則
- 1つのモノを複数の分類に
- 実装の再利用に便利な多重継承
- 解決策1 多重継承を禁止する
- 委譲
- インタフェース
- 解決策2 メソッド解決順序を工夫する
- 深さ優先探索の問題点
- C3線形化で順序を決める
- 解決策3 処理を混ぜ込む(Mix-in)
- Pythonの場合
- Rubyの場合
- 解決策4 トレイト
- 名前が衝突したときの振る舞い
- 提供するメソッドと要求するメソッド
- ほかにもいろいろな機能が……
- トレイトが広まりつつある
- 【Column】端から順番に写経する