magazine.gifコーディングを支える技術

はじめに
謝辞
本書の構成

  • サンプルコードのダウンロード

第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のパッケージでオブジェクトを作る
    • モジュールだけでは足りない
    • データ置き場は個別に
    • 引数に個別のハッシュを渡す
    • 初期化の処理もパッケージに入れる
    • ハッシュとパッケージを結び付ける
  • 11.4 方法2 関数もハッシュに入れる
    • ファーストクラス
    • 関数をハッシュに入れる
    • 複数のカウンタを作る
    • 共有してよいモノをプロトタイプに移す
      • プロトタイプの動作
      • new演算子で効率的に記述する
    • これがオブジェクト指向?
  • 11.5 方法3 クロージャ
    • クロージャとは
    • なぜクロージャと呼ぶ?
  • 11.6 方法4 クラス
    • Hoareの考えたクラス
    • C++のクラス
    • 仕様としての役割
    • クラスが持つ3つの役割
  • 11.7 まとめ

第12章 継承によるコードの再利用

  • 12.1 継承とは
    • 継承に対するさまざまな考え方
      • 一般化/特殊化
      • 共通部分の抽出
      • 差分実装
    • 継承は諸刃の剣
    • リスコフの置換原則
  • 12.2 多重継承
    • 1つのモノを複数の分類に
    • 実装の再利用に便利な多重継承
  • 12.3 多重継承の問題点──またしても衝突!
    • 解決策1 多重継承を禁止する
      • 委譲
      • インタフェース
    • 解決策2 メソッド解決順序を工夫する
      • 深さ優先探索の問題点
      • C3線形化で順序を決める
    • 解決策3 処理を混ぜ込む(Mix-in)
      • Pythonの場合
      • Rubyの場合
    • 解決策4 トレイト
      • 名前が衝突したときの振る舞い
      • 提供するメソッドと要求するメソッド
      • ほかにもいろいろな機能が……
      • トレイトが広まりつつある
  • 12.4 まとめ
    • 【Column】端から順番に写経する

あとがき
索引