要約
このレッスンはコースの最初の単元をなし、その学習計画の全体を示す。コースの目的が、特定の言語ではなくプログラミングそのものであることを述べ、その基礎を、もっと学びやすい言語ではなく、機械を隠さない言語である C++ で教える理由を説明する。また、対象とする学生、前提とするわずかな知識、この先につながるコースを示し、七つの全体的な学習目標と、それぞれに寄与する単元を述べ、八つの内容単元とそれを構成するレッスンを説明する。さらに、コースが求める学習量の合計、その単元ごとの配分、推奨する学習ペース、単位数を見積もり、レッスンの作り方を説明し、最後に、このコースの学び方、人工知能アシスタントの使い方、バージョン管理について助言する。
学習目標
- コースの八つの単元の順序を説明し、各単元がその後の単元に何をもたらすかを説明する。
- コースの七つの全体的な学習目標を述べ、どの単元がそれぞれの目標に寄与するかを見分ける。
- このコースがプログラミングの基礎を、型とメモリを隠す言語ではなく C++ で教える理由を、例を挙げて説明する。
- 単元ごとの見積もり時間から、コースまたはその一部が求める学習量を計算し、それをもとに自分の学習ペースを計画する。
目的
このコースは、正しいプログラムを一から書くことを教える。言葉で述べられた問題を正確な命令の列に変え、データの表し方を選び、書いたものが実行される順序を制御し、コードを明確なインタフェースをもつ関数にまとめることである。そうであれば、このコースの対象は一つの言語ではなく、プログラミングそのもの、すなわちアルゴリズムを考え、データを表し、問題を分解し、書いたものの正しさとコストについて推論することである。だからこそ、このコースは「プログラミングの基礎」と名づけられており、だからこそ C++ の構文要素はどれも、それが解決する問題とそれについての推論の仕方とともに示され、決して構文の一覧としては示されない。
したがって、C++ はこのコースの道具であって、目的ではない。とはいえ、道具はそれを使って学ぶことに無関係ではなく、一見もっとも難しく思えるこの道具を選んだのは意図してのことである。その理由は後の節で述べる。ただし、その最も目に見える帰結を先に述べておきたい。各単元のまとめのレッスンには「どの言語でも通用すること」という決まった節があり、学んだことを C++ での形から切り離し、ほかの言語ではそれがどう表されるか、あるいは何が変わるかを述べる。ここから、このコースを修了した学生は、C++ で書けるようになるだけでなく、どの言語においても、装いを変えた同じ考え方を見抜けるようになる。
なぜ C++ で、もっと優しい言語ではないのか
Python のように学習曲線がもっと緩やかな言語もあり、そこでは最初の役に立つプログラムが、型を宣言することも、コンパイルすることも、データがどこにあるのかを問うこともなく、数行で書ける。動くプログラムを早く書くことが目的なら、それが進むべき道だろう。しかし、このコースの目的は、プログラムが何をしているのかを理解することであり、そのためには機械を隠さない言語がふさわしい。C++ は、より手軽な言語が黙って片づけてしまう六つのことを見るよう求める。
- 型。 どのデータも型とともに宣言され、型は、そのデータが取りうる値、占める大きさ、許される演算を定める。コンパイラは、何かを実行する前に、合わないものを拒否する。
- コンパイル。 書くこと、コンパイルすること、リンクすること、実行することは別々の段階であり、どのエラーもそのどれかに属する。どの段階に属するかがわかれば、直す作業の半分は済んでいる。
- メモリ。 変数は、生存期間とスコープをもつ、名前のついたメモリの区画である。参照は同じ区画の別名であり、もう存在しない区画への参照は現実のエラーである。
- コピーのコスト。 ベクターを関数に渡すと、全体がコピーされることがある。値渡しと参照渡しのどちらを選ぶかは、機械ではなくプログラムを書く人が決めることである。
- 数の限界。 32 ビットの整数は を超えず、浮動小数点数は を正確には保持できない。
- 未定義動作。 規格が定義していないこと(配列の範囲外へのアクセス、符号付き整数のオーバーフロー、初期化されていない変数の読み取り)は、エラーを保証するのではなく、何が起きてもおかしくない。そのため、このコースは常に警告とサニタイザを有効にしてコンパイルする。
次の例が、それを小さな規模で示す。このプログラムは、int 型の変数で から までの階乗を計算する。整数が際限なく大きくなる Python なら、同じ計算は文句も言わずに を表示するだろう。C++ では、 と の積は int に収まらず、このコースがすべての例のコンパイルに用いている未定義動作のサニタイザが、まさにその行でプログラムを止める。
#include <print>int main(){ int factorial{1}; for (int n{1}; n <= 15; ++n) { factorial = factorial * n; // 積は int に収まるか? std::println("{}! = {}", n, factorial); }}1! = 12! = 23! = 64! = 245! = 1206! = 7207! = 50408! = 403209! = 36288010! = 362880011! = 3991680012! = 479001600main.cpp:7:31: runtime error: signed integer overflow: 479001600 * 13 cannot be represented in type 'int'プログラムはコード 1 で終了しました。
そうであれば、この言語は、もう一方の言語なら隠してしまう問いを立てるよう求めたことになる。選んだ型にどれだけ収まるのか、収まらないときにどうするのか、という問いである。二つの答えのどちらが抽象的に優れているということはない。大切なのは、その問いが存在すると知っていることである。整数とその表現 のレッスンがこの問いに答え、各まとめのレッスンの未定義動作についての節が、ふたたびこの問いに立ち返る。
ここから一つの非対称性が生じ、それがこの選択の根本的な理由である。基礎を C++ で学んだ人は、のちに、より手軽な言語が自分の代わりに何をしてくれているのかを理解する。ガベージコレクタ、上限のない整数、添字のチェック、型の暗黙の変換である。一方、先にそうした言語で学んだ人は、これらの層を見ないまま過ごし、あとになって、言語が隠していた原因のどれかで実際のプログラムが失敗したときに、それにつまずく。したがって、このコースが選ぶ道は、はじめは厳しいが、ほかへ持ち越しやすい。ここで学んだことはどの言語でも通用するが、それを隠す言語で学んだことは、ここでは必ずしも通用しない。
とはいえ、C++ は大きな言語であり、基礎のコースはそのすべてを教えたくなる誘惑に抗わなければならない。この最初のコースは、C++23 規格の構造化プログラミング(データ、式、制御フロー、列、テキスト、関数)に絞り、その現代的な書き方を用いる。std::println による出力、std::array と std::vector による列、std::string によるテキスト、レンジの形でのライブラリのアルゴリズムである。この土台を必要とするもの、すなわちポインタと動的メモリ、メンバ関数をもつクラス、自作のテンプレート、無名関数、例外は、C++ プログラミング II に回す。
対象と前提知識
このコースは、プログラムを一度も書いたことのない人を対象とし、どの学修プログラムの学生でも、一年次から受講できる。データ構造やシステムのコースの前にしっかりした土台を必要とする情報系の学生、コンピュータをやみくもに信用せずに計算に使う必要のある工学系や理学系の学生、自分のアルゴリズムが実行されるプログラムになるのを見たい数学系の学生である。
これはレベル 1 のコースで、前提となる科目はなく、それだけで完結している。前提とするのは二つのことだけである。割り算の商と余りを含む学校の算数と、コンピュータの初歩的な操作(フォルダを作る、ファイルを保存する、プログラムを開く)である。二進表現、場合分けによる推論、条件の論理、帰納法のうち使うものは、必要になった箇所で教える。二進法は整数のレッスンで、ド・モルガンの法則は関係と論理のレッスンで、帰納法は再帰のレッスンで扱う。したがって、各レッスンに現れるサイトのほかのコースへの参照は、理解を深めるためのものであって、前提条件ではない。
どこへ通じるか
以上から、サイトにおけるこのコースの位置が決まる。前提となる科目はなく、「情報学と計算」と「工学」という二つの学修プログラムの目標となるコースである。どちらにおいても、プログラミングは道具であると同時に対象だからである。そのため、これらのプログラムの最初のコースの一つとして、学術文書作成のための LaTeX や 数理論理学 I:命題論理 とともに受講するのがよい。
このコースには補完的なコースが一つあり、その前でも、並行してでも、あとでも受講できる。数理論理学 I:命題論理 は、ここで実践として使うことを理論として学ぶ。単元 3 の複合条件、真理値表、ド・モルガンの法則、そして手続きが正しいことを証明するという考え方であり、この考え方はこのコースではループの不変条件と再帰についての帰納法の形をとる。一方、代数と幾何 I は、このコースがプログラムにする数についての結果を証明する。ユークリッド除法、ユークリッドの互除法、記数法、ホーナー法である。そして 学術文書作成のための LaTeX は、そのレッスン 共同執筆 で、Git によるバージョン管理を教える。このコースは、最初のプログラムからそれを使うことを勧める。
とはいえ、このコースは、自身の土台を必要とするものを意図的に外している。予定されている続きは C++ プログラミング II であり、ポインタと動的メモリ、クラスとオブジェクト、テンプレート、無名関数、例外、そして標準ライブラリを深く扱う。ここから、このコースは C++ の手引き書の最初の部分ではなく、ここで終えることのできる、完結した基礎のコースである。一方、先に進む人は、コース II で、同じ規律が、もはやそれなしでは済まない大きさのプログラムに適用されるのを見ることになる。
全体的な学習目標
以下の目標は、コースを修了した学生ができるようになるべきことを述べる。それぞれ観察可能な行為として定式化されており、具体的な課題で確かめることができる。内容を扱う各レッスンもそれぞれ固有の目標を掲げ、それらは一つ以上の全体目標に役立つ。まとめのレッスンは、各目標がどの単元とどのレッスンで扱われるかを示す。七つの目標には、引用できるように番号を付ける。
- 目標 1。 プログラムで問題を解く。何を入力し何を出力するかの仕様を定め、アルゴリズムを設計し、それを手で追い、書き、コンパイルし、実行し、デバッグする。その際、コンパイラのメッセージと警告を読み解く。
- 目標 2。 各データに適切な型を選び、その表現の限界について推論する。整数の値の範囲、オーバーフロー、浮動小数点の丸め、テキストのエンコーディングである。
- 目標 3。 優先順位、型変換、副作用、規格が未定義のまま残すことを知ったうえで、正しい式を組み立てる。
- 目標 4。 正しく、かつ停止する分岐とループで制御フローを設計し、その正しさを不変条件で根拠づける。
- 目標 5。 問題を明確なインタフェースをもつ関数に分解し、引数の渡し方を選び、再帰で問題を解く。
- 目標 6。 複合データ(列、表、レコード、テキスト、ファイル)を、基本的なアルゴリズムと標準ライブラリで表現し処理し、そのコストを見積もる。
- 目標 7。 より大きなプログラムを複数のファイルに整理し、事前条件と事後条件で仕様を定め、体系的にテストし、その正しさを論証する。
五つの目標には、それぞれの単元がある。目標 2 はデータと型の単元、目標 3 は式の単元、目標 4 は制御フローの単元、目標 5 は関数の単元、目標 6 は複合データの単元であり、最後のものはテキストとファイルの単元に引き継がれ、そこで目標 2 が UTF-8 エンコーディングとともにふたたび現れる。残りの二つは、これに対して、コース全体を貫いている。目標 1 は、仕様を定め、書き、コンパイルし、実行するという作業の流れを教える最初の単元と、最後の単元のデバッグのレッスンを主な場とする。しかし、コースのどのプログラムもコンパイルされ、実行され、修正されるので、すべての単元で練習される。目標 7 は、最後の単元、すなわちより大きなプログラムの単元を主な場とする。しかし、最初の単元のスタイルガイドに始まり、二番目の単元の定数に続き、五番目の単元の契約(以後、どの関数にも伴う)と四番目と六番目の単元の不変条件で形をとる。ここから、これら二つの目標の達成は一つの単元に帰することができず、コース全体を通じて育てるのがよいことがわかる。
内容
このコースは十の単元で構成される。この紹介、八つの内容単元、そして締めくくりである。各内容単元は導入のレッスンで始まり、そのレッスンは単元の各レッスン、前提とする知識、単元が解決する問題を示し、冒頭に導入テストを置く。単元は、まとめのレッスンで終わる。まとめのレッスンは単元の概念の連鎖を組み立て直し、どの言語でも通用することを C++ での形から切り離し、単元の未定義動作をまとめ、まとめテストで導入テストの技能をもう一度問い、各レッスンの問題より難しい挑戦課題を出す。
第 0 単元 コースの紹介
このレッスンだけからなり、コースの目的、言語の選択、全体目標、内容、学習量、設計を定める。
第 1 単元 はじめの一歩
その目標は、言葉で述べられた問題から、コンパイルでき、実行でき、データを読み、結果を書くプログラムまで学生を導き、その途中で各道具が何をしたのかをわかるようにすることである。アルゴリズムはプログラムに先立つので、コードなしで始まる。終わったとき、学生は C++ についてまだ少ししか知らないが、C++ でどう作業するかは知っている。
- C++ のはじめの一歩:導入。
- 問題からアルゴリズムへ:入力と出力の仕様、番号付きの手順、手によるトレース、順次、分岐、反復。
- プログラム・コンパイラ・C++:前処理、コンパイル、リンク。コンパイル言語とインタプリタ言語の対比。言語の規格。
- Windows・macOS・Linux での環境構築:三つの完全な手引き、コンパイラ、Visual Studio Code とその C++ 拡張機能、動作の確認、よくある問題。
- コンパイル・実行・設定:このコースのオプション、エラーと警告、サニタイザ、エディタのビルド タスク、コンソールのエンコーディング。
- プログラムの解剖:インクルード、
main、文、ブロック、コメント、このコースのスタイルガイド。 - 入力・出力・エラー:
std::cin、std::printlnと書式指定、期待どおりでない入力、エラーの分類。 - C++ のはじめの一歩:まとめと挑戦課題。
第 2 単元 データと型
その目標は、どのデータも型とともにメモリの中にあり、型がそのデータの取りうる値、占める大きさ、許される演算を定めること、そしてプログラムの中の数は数学の数ではなく、限界のある表現であることを教えることである。
- データと型:導入。
- 変数とメモリ:宣言と波括弧による初期化、代入、状態のトレース、名前、初期化されていない変数。
- 整数とその表現:基数 2 と 16、各型の値の範囲、2 の補数、符号付きと符号なしのオーバーフロー。
- 浮動小数点数: が正確でない理由、丸めの蓄積、許容誤差による比較、無限大と非数(NaN)。
- 文字・真偽値・型変換・定数:文字の文字コード、暗黙の型変換と明示的な型変換、情報を失う型変換の拒否、
const、constexpr、auto。 - データと型:まとめと挑戦課題。
第 3 単元 式と演算子
その目標は、値を確実に予測できる式の組み立て方を教えることである。どの演算が先に行われるか、結果がどの型になるか、どんな副作用があるか、どの式が意味をもたないかである。この単元にはまだ分岐もループもない。条件は計算され、表示される。
- 式と演算子:導入。
- 算術演算:負の数の商と余り、式の木、優先順位、結合規則、結果の型。
- 関係と論理:複合条件、ド・モルガンの法則によるその否定、短絡評価、
1 < x < 5の誤り。 - 代入・副作用・未定義動作:式の値と作用、インクリメント、評価順序、規格が定義しないことの一覧。
- ビットと数学ライブラリ:ビット演算子、シフト、マスク、
<cmath>、<numbers>の定数。 - 式と演算子:まとめと挑戦課題。
第 4 単元 制御フロー
その目標は、分岐とループで実行の順序を制御し、その正しさについて推論すること、すなわち、どの場合も処理され、どのループもなすべきことをし、そして停止することを教えることである。この単元は、コースの最初のレッスンが予告したこと、すなわち分岐と反復を、今度はコードに書いて確かめる形で実現する。
- 制御フロー:導入。
- 分岐:連鎖した
ifとelseと入れ子のifとelse、互いに重ならず網羅的な場合分け、enum classを使うswitchとその落とし穴。 - ループ:
while、do、for、ループのトレース、形どうしの書き換え、入れ子のループ。 - 正しいループの設計:カウンタ、累積変数、最大値、番兵のパターン、不変条件、停止性、デバッガとの最初の出会い。
- 数値アルゴリズム:素数判定、ユークリッドの互除法、基数変換、ホーナー法、二分法。いずれも根拠を添える。
- 制御フロー:まとめと挑戦課題。
第 5 単元 関数
その目標は、問題を、それぞれインタフェースと契約をもつ名前のついた部分に分解すること、そして再帰で問題を解くことを教えることである。この単元は、単元 4 の長いプログラムを、一つずつ確かめられる部分から組み立てたプログラムに変える。
- 関数:導入。
- 関数:宣言、定義、呼び出し、コールスタック、事前条件と事後条件、値を返さない関数。
- 引数とスコープ:値渡し、参照渡し、const 参照渡し、構造化束縛による複数の結果、変数のスコープと生存期間。
- 関数による設計:段階的詳細化、本体より先にインタフェース、「一つの関数に一つの仕事」という規則、オーバーロード。
- 再帰:基底と再帰段階、帰納法による正しさと停止性、スタックと再帰のコスト。
- 関数:まとめと挑戦課題。
第 6 単元 複合データ
その目標は、データの集まりを表現し、それを手で書いたアルゴリズムやライブラリから取ったアルゴリズムで処理し、そのコストを見積もることを教えることである。この単元は、ばらばらのデータからコレクションへ、そして「正しいか」という問いから「どれだけかかるか」という問いへと導く。
- 複合データ:導入。
- 配列:
std::array、添字による走査と範囲for文による走査、範囲内の添字、対比としての C 言語の配列。 - ベクター:
std::vector、長さのわからない並びの読み取り、集約・抽出・変換、サイズと容量。 - アルゴリズムのコスト:支配的な演算の数え上げ、増加のオーダー、時間の測定。
- 探索とソート:線形探索と二分探索、選択ソートと挿入ソートとその不変条件、ライブラリのアルゴリズム。
- 表:二次元の表、行ごとと列ごとの走査、転置、積、一次元化したベクターの中の表。
- レコード:
struct、指示付き初期化子、引数としてのレコード、フィールドによるソート。 - 複合データ:まとめと挑戦課題。
第 7 単元 テキストとファイル
その目標は、テキストをデータとして扱うこと、そしてプログラムが、形式の誤った入力に出会っても壊れずにファイルを読み書きできるようにすることを教えることである。終わったとき、学生は、アクセント記号や誤りを含む現実のデータを処理するプログラムを書けるようになっている。
- テキストとファイル:導入。
- 文字列:
std::stringとその操作、npos、std::string_viewによるビュー、対比としての C 文字列。 - テキストは ASCII ではない:UTF-8 エンコーディング、バイトと文字、テキストを壊す操作。
- 入力を正しく読む:
std::getline、ストリームの状態、不正なデータのあとの回復、std::from_charsによる検証。 - テキストファイル:開く、一行ずつ読む、書く、追記する、そしてカンマ区切りの値のファイルを処理する。
- テキストとファイル:まとめと挑戦課題。
第 8 単元 より大きなプログラム
その目標は、もはや一つのファイルにも頭の中にも収まらないプログラムを整理し、確かめ、デバッグすることを教えることである。この単元は、最初のレッスンが始めた循環、すなわち仕様を定め、作り、確かめるという循環を閉じる。そのまとめのレッスンは、コース全体を総合する最終プロジェクトで終わる。
- より大きなプログラム:導入。
- 複数ファイルと自作ライブラリ:ヘッダと実装、インクルードガード、単一定義規則、分割コンパイル。
- プログラムのテスト:仕様から導くテストケース、自動テスト、
assertとstatic_assert。 - プログラムのデバッグ:Visual Studio Code のデバッガ、ブレークポイント、コールスタック、エラーの場所を突き止める体系的な戦略。
- より大きなプログラム:まとめと挑戦課題。
第 9 単元 コースのまとめ
C++ プログラミング I:最終総括 のレッスンからなる。このレッスンは七つの全体目標を振り返り、各目標がどの単元とどのレッスンで扱われたかを図で示し、まとめテストの初回の回答を目標ごとに集計し、学びがどこへ続くかを示す。
学習量と単位
コースの学習量は講義時間では測らない。非同期のコースには講義時間がないからである。測るのは学生の作業の総量、すなわち読むこと、例を書いてコンパイルすること、問題を解くこと、復習することである。見積もりは、サイトのすべてのコースで同じ方法による。各レッスンの本文(例のコードを含む)を一分あたり百語で読む時間、例題一題につき二十分、練習問題一題につき三十五分、挑戦課題一題につき四十五分、導入テストまたはまとめテスト一回につき十二分を数え、復習のために一割の余裕を加える。
結果
このコースのレッスンには、全体で例題が 題、練習問題が 題、挑戦課題が 題あり、ほかに単元のテストが十六回と、サイトがその場で確認する短い演習が七十ある。単元ごとの見積もり学習量は、時間単位に丸めて次のとおりである。
- 第 0 単元、コースの紹介: 時間。
- 第 1 単元、はじめの一歩: 時間。
- 第 2 単元、データと型: 時間。
- 第 3 単元、式と演算子: 時間。
- 第 4 単元、制御フロー: 時間。
- 第 5 単元、関数: 時間。
- 第 6 単元、複合データ: 時間。
- 第 7 単元、テキストとファイル: 時間。
- 第 8 単元、より大きなプログラム: 時間。
- 第 9 単元、コースのまとめ: 時間未満。
合計は学生の作業でおよそ 時間である。この数字は、ありのままに受け取るのがよい。すなわち、すべての例を書いてコンパイルし、すべての問題と挑戦課題を解く学生についての見積もりである。ほかの言語でプログラムを書いたことのある人は、最初の単元でかなり少ない時間で済むだろう。プログラムをインストールしたこともエラーメッセージを読んだこともない人は、もっと必要かもしれない。とくに単元 1 ではそうであり、この単元は、複合データの単元とともに、もっとも分量の多い単元でもある。
とはいえ、この数字は名目上のものである。コースの単位数を決めるのはこの数字であり、一定のペースで読むことと、挑戦課題一題につき四十五分を前提としている。実際の学生で測るまでは、現実的な幅を添えておくのがよい。読む速さが想定の半分で(各例を手で書き、コンパイルし、何が変わるかを見るために手を加えるとそうなる)、挑戦課題一題に四十五分ではなく七十五分かかるとすれば、同じ方法でおよそ 時間になる。したがって、見込まれる学習量はおよそ 時間からおよそ 時間のあいだにある。上の端は慎重な上限であって、測定値ではない。この幅は、コースを学ぶ人が実際にかける時間がわかった時点で修正し、それまでは単位数を名目上の数字で計算する。
推奨するペース
ペースを呼び分けるため、この計画はサイトのほかの学習計画と同じ基準を用いる。フルタイムとは 単位の一学年、およそ 時間をおよそ四十週に配分したもの、すなわち週におよそ 時間であり、パートタイムはその半分、週におよそ 時間である。ここから、推奨するペースは十六週の一学期で、週におよそ 時間の学習となる。これはフルタイムの三分の一をやや下回る。現実的な幅で見れば、週に 時間から 時間である。この学期は 数理論理学 I:命題論理 と並行して受講できる。その真理値表と証明の考え方は、このコースの条件と不変条件の中に見て取れる。
週におよそ 時間、すなわちパートタイムの集中的なペースなら、コースを九週か十週で終えられる。週におよそ 時間のゆるやかなペースなら、二学期にわたり、ほぼ半分ずつに分かれる。アルゴリズムから制御フローまでの単元 0 から 4 がおよそ 時間、関数から最終プロジェクトまでの単元 5 から 9 がおよそ 時間である。この区切りは自然である。単元 4 を終えたとき、学生はすでに一つの main の中で完結したプログラムを書いており、後半はそれを整理することを教える。
単位
このサイトの単位は、コースが学ぶ人に求める学習の総量(読むこと、問題、挑戦課題、復習)を測るものであり、授業の時間を測るものではない。一単位はおよそ 時間の学習にあたり、フルタイムの一年は 単位、すなわちおよそ 時間にあたる。これは、前の項でペースを呼び分けるのに用いたのと同じ基準である。
さて、見積もった 時間を で割ると 6.8 が得られ、これを丸めて とする。一単位の幅を 時間から 時間の学習と認めるなら、このコースの単位数 は 6.3 と 7.5 のあいだに挟まれる。
したがって、このコースは 単位であり、フルタイムの一年の九分の一をやや上回る。この数字は見落としではない。コースは基礎を教えるのに必要なだけの長さがあり、きりのよい単位数に合わせるために削られてはいない。
単位の効用は実際的なものである。単位によって、サイトのコースどうしの負担を比べ、使える時間を超えずに同時にいくつ学ぶのがよいかを決めることができる。たとえば、十六週の一学期をパートタイムで、すなわちおよそ 時間を使える人は、合計およそ 単位のコースに取り組むことができる。同じ学期をフルタイムで使えるなら、およそ 単位である。
これらの単位は、学習を計画するためにこのサイトが独自に用いる尺度であり、いかなる公的な単位制度にも対応せず、いかなる機関による学術的な認定を意味するものでもない。
コースの設計
形態
このコースは非同期・オンライン・自分のペースで進める形態である。日程も、ライブの授業も、締め切りもなく、学生はそれぞれ自分の準備と時間が許す速さで進む。このコースはサイトの十四の言語で提供される予定である。プログラムの識別子は英語で、すべての版で同じである。一方、コメントとプログラムが表示するメッセージはページの言語で書かれており、それぞれの版は独自の出力をもってコンパイルされ実行される。各レッスンは、先に学んでおくとよいほかのレッスンを明示しているので、推奨される順序ははっきりしている。
一つの課の構成
内容を扱うレッスンはすべて同じ構成をとる。冒頭に要約と、観察可能な行為として定式化された固有の学習目標の一覧がある。続いて解説があり、その核はプログラムである。コースの完全なプログラムはどれも、サイトを構築する前に、C++23 規格で、すべての警告を有効にし、メモリエラーと未定義動作のサニタイザを付けてコンパイルされ、実行された。コードの下に載っているのはその実際の出力であり、教える内容がエラーや警告であるときはコンパイラの実際のメッセージ、プログラムが未定義動作を起こすときはサニタイザの実際のレポートである。そうであれば、このコースの出力に手で書かれたものは一つもない。サイトは構築時に、どのプログラムにも現在の版の出力が保存されていることを確かめ、一つでも欠けていれば公開されない。ほかの図は、本文が推論することを段階を追って動かして見せる。名前と値をもつメモリの区画、コールスタック、ループの進み方、数のビットである。
各レッスンの最後には、段階を追った解答付きの例題が三題と、練習問題が三題ある。練習問題にはそれぞれ折りたたまれたヒントがあり、そのあとに答えがあり、ときには詳しい解答が添えられている。詳しい解答は、自分の解答を書いてから開くのがよい。問題が求めるのは一つの発想であって、例の機械的な繰り返しでは決してなく、そのレッスンまでに教えたことだけを使う。各レッスンには、さらに、サイトがその場で確認する短い演習が二つある。一つはプログラムの正確な出力を予測するもの、もう一つはコードの断片を補うか直すものである。この確認が何をし、何をしないかは知っておくのがよい。サイトは学生のコードをコンパイルせず、本質的な部分があることと、狙いのエラーが消えたことをパターンで確かめる。したがって、サイトで合格した演習も、やはり自分のコンピュータでコンパイルし実行しなければならない。そこが唯一の最終的な審判である。
導入のレッスンとまとめのレッスンには独自の構成がある。導入は、単元、その各レッスン、それらをつなぐ筋道、前提とする知識、単元が解決する問題を示し、導入テストを含む。まとめは、単元の概念の連鎖を、各環が確立されるレッスンと、それぞれが用いるものとともに組み立て直す。まとめには「どの言語でも通用すること」と「単元の未定義動作」という二つの決まった節、まとめテスト、六つの挑戦課題(最後の単元では十。その最終プロジェクトは段階に分けられる)があり、挑戦課題にはそれぞれヒントと答えがあり、推論にその価値があるときは、折りたたまれた詳しい解答が付く。
音声読み上げ
どのレッスンも、端末そのものの音声を使うサイトの読み上げ機能で、声に出して聞くことができる。本文は書かれたとおりに読まれ、本文中に引用されたコードは意味の通るように発音され、コードの例は告げられるだけで、一文字ずつ読まれることはない。これにより、画面から離れて解説を復習できる。一方、プログラムには常にエディタが必要である。
評価
このコースは成績をつけない。学習の確認は形成的なもので、自己チェックに基づく。練習問題で各レッスンの目標の達成を、挑戦課題で各単元の目標の達成を確かめることができる。そのいずれでも、最後の審判は、警告とサニタイザを備えたコンパイラである。警告なしにコンパイルされ、自分のテストケースを通り、どのサニタイザも目を覚まさないプログラムは、議論の余地のない証拠だからである。もっとも、テストのレッスンが教えるとおり、それは証明ではない。
これに単元のテストが加わる。導入のレッスンにある導入テストは短い自己チェックで、出発点を測る。まとめのレッスンで挑戦課題の前にあるまとめテストは、達成したことを測り、導入テストと比較される。どちらもブラウザーの中でそのまま採点される。各回答には説明が付き、典型的な誤りにはそれを特定するコメントが付き、各問題は復習すべきレッスンを示す。どちらも成績をつけることも認定することもなく、結果は学生のブラウザーにだけ保存される。身につけた技能の認定は、のちに別のプラットフォームで行う。最終総括は、各まとめテストの初回の回答を全体目標ごとのプロフィールにまとめる。
人工知能アシスタント
今日では、このコースのほとんどどんな問題の解答も数秒で書ける人工知能アシスタントがある。それらにふさわしい位置をはっきり述べておくのがよい。その理由は、ほかのすべてを根拠づけている理由と同じである。このコースが鍛えるのはプログラムの生産ではなく、一つの能力、すなわち問題を考え抜いて正しいプログラムに変える能力である。そうであれば、演習をアシスタントに任せることは演習を無にすることであり、それはちょうど、取り組む前に問題の答えを見ると、その問題がただの読み物になるのと同じである。できあがったプログラムは正しいかもしれない。しかし、それを提出する人は書き方を学んでおらず、アシスタントが間違えたとき、すなわちまさにその力がもっとも必要なときに、書くことができない。
ここから導かれるのは、禁止ではなく、使い方の規則である。アシスタントは、理解できないエラーメッセージの説明、思いつかなかったテストケースの提案、すでに書き上げた自分の解答と別の解答との比較、解説の考え方を別の角度から明らかにすることに役立つ。演習、問題、挑戦課題を書くことには役立たない。そして、どんな場合にも、アシスタントから来たものであれ、フォーラムから来たものであれ、仲間から来たものであれ、あらゆる他人のコードに通用する原則がある。受け入れる前に、読み、テストし、理解することである。アシスタントは、コンパイルが通り、正しく見えるのに、未定義動作を起こしたり、言語の古い書き方を使ったりするコードを出すことがある。このコースをやり遂げた学生はそれを見抜けるが、コースを他人任せにした学生には見抜けない。
このコースの学び方
このコースは順番に学ぶように作られている。各単元はそれ以前の単元を前提とする。式は二番目の単元の型で書かれ、ループは三番目の単元の式で書かれ、関数は四番目の単元のループを包み込み、複合データは関数で処理される。レッスンを飛ばすと、遅かれ早かれそこへ戻らなければならなくなる。
主な規則はただ一つ、すべての例を書いてコンパイルすることである。プログラミングは読むことによってではなく、書き、コンパイルし、コンパイラが返すものを読むことによって身につく。そのため、学生は Windows・macOS・Linux での環境構築 のレッスンに従って自分の環境をインストールし、コンパイル・実行・設定 のレッスンが設定の仕方を教えるオプションを使って、すべてのプログラムを自分の Visual Studio Code で再現する。プログラムをインストールできないコンピュータを使う人は、暫定的にオンラインコンパイラを使うことができ、それについてはインストールのレッスンが説明している。例はコピーせずに手で書くのがよい。目が見落とすものを手は覚えているからである。各プログラムの出力は、実行する前に予測するのがよい。予測と結果の差こそ、まだ学ぶべきことだからである。そして、コンパイラの警告は、どれも我慢すべき雑音ではなく、答えるに値する問いとして読むのがよい。プログラムが動いたら、さらにわざと手を加え(セミコロンを消す、型を変える、ベクターの範囲外に出る)、コンパイラやサニタイザが何と言うかを読むのがよい。わざと起こしたエラーは、どれもあとで見分けられるエラーになるからである。
各単元には二つの確認点がある。導入のレッスンにある導入テストは出発点である。単元を学ぶ前に、何も参照せずに答え、誤りが示すレッスンを書き留めておくのがよい。まとめのレッスンで挑戦課題の前にあるまとめテストは照合である。レッスンを終えたところで、やはり何も参照せずに答え、導入テストと比べる。どちらでも数えるのは初回の回答であり、比較されるのも、最終総括のプロフィールにまとめられるのもそれである。練習問題と挑戦課題では、ヒントは取り組みが尽きたときにだけ開き、答えは確かめるために最後にだけ開くのがよい。自分の解答をコンパイルする前に答えを見た問題は、解いたのではなく、読んだのである。
バージョン管理
最後に、最初のプログラムから、コースでの作業をバージョン管理システムで保存しておくのがよい。Git は作業フォルダの各状態を記録し、そのどれにでも戻れるようにし、二つの状態のあいだで何が変わったかを示す。プログラムを書く人にとって、これは、動いていたものを失う心配なしに試せること、そしてバージョンを比べてエラーを持ち込んだ変更を突き止められることを意味する。後者は、デバッグのレッスンが教える二分探索による絞り込みを、プログラムの履歴に持ち込むことである。このコースは Git を教えない。サイトの別のコースがすでに教えているからである。学術文書作成のための LaTeX のコースのレッスン 共同執筆 が、最小限の作業手順、どのファイルを保存しどのファイルを除外するか、競合をどう解消するかを説明している。そこで文書のソースについて言えることは、プログラムのソースについてもそのまま言える。LaTeX の補助ファイルの代わりに、コンパイルが作り直す実行ファイルとオブジェクトファイルを除外すればよい。