Dev Study
← 研修トップ

どの言語にもある仕組み — 値・型・数・文字・エラー・メモリ・並行

`b = a` は何をコピーするのか。const は何を固定するのか。0.1+0.2 は計算の誤りなのか。文字列の長さは何を数えているのか。例外と戻り値で、エラーの無視はどれだけ目立つのか。GC があればファイルは閉じられるのか。await の前後で何が割り込むのか。同じ1行を Python・JavaScript・Go・Rust・C で書くと、ある言語では止まり、ある言語では黙って別の値になります。違いは文法ではなく、仕様が何を約束し、何を実装に任せたかにあります。各言語の公式仕様と、コンテナで並べて動かした実演から積み上げます。

  1. 1
    代入は何をコピーするか — 名前と実体と、言語ごとの約束
    `b = a` で複製されるものは言語ごとに違います。Python のリストと JavaScript の配列では実体を指す参照が、Go の配列では中身が、Go のスライスでは配列の一部を指す小さな記述子が複製されます。Rust の Vec ではポインタ・長さ・容量が複製されますが、元の a は使えなくなります(move)。
    約 8 分
  2. 2
    const が固定するのは名前 — 中身まで凍るかは言語が決める
    JavaScript の const が固定するのは「名前がどの実体を指すか」(束縛)だけで、指した先の配列やオブジェクトの中身は変えられます。
    約 8 分
  3. 3
    型を確かめるのは誰で、いつか
    型の食い違いを見つける役は、言語ごとに違います。実行前のコンパイラか、実行中の演算か、それとも誰も見ないかです。
    約 8 分
  4. 4
    「無い」をどう表すか — null・nil・Option
    「値が無い」の表し方は言語ごとに違います。JavaScript は undefined と null という2つの値を持ち、Go は型ごとの nil を持ち、Rust は Option という型で「有るか無いか」を包みます。
    約 8 分
  5. 5
    整数には端がある — あふれた後に何が起きるかは言語が決める
    固定幅の整数には表せる範囲の端があり、端を越えた後に何が起きるかは言語ごとに約束が違います。折り返す(Go、C の符号なし、Rust の release は rustc の選択)、止まる(Rust の debug)、そもそもあふれない(Python の int)、そして C の符号付きは「未定義」です。
    約 8 分
  6. 6
    浮動小数点は1回ごとに正しく丸める — 0.1+0.2 のずれはどこで入るか
    0.1+0.2 が 0.30000000000000004 になるのは、足し算が雑だからではありません。0.1 と 0.2 は格納する時点で丸められており、足し算はその2つの正確な和を最も近い double に丸めています。今回は正確な和が上下の double のちょうど中間にあり、偶数丸めで上側が選ばれました。
    約 9 分
  7. 7
    文字列は文字の列ではない — 切ると壊れる単位
    文字列の添字や長さが数えている「要素」は言語ごとに違います。JavaScript は16ビットの値、Python はコードポイント、Go はバイト、Rust は UTF-8 のバイトです。どれも、人が1文字と見るものとは一致しません。
    約 8 分
  8. 8
    等しいとは何か — == とハッシュの約束
    集合や辞書は、鍵をまずハッシュ値で探す場所を決め、その場所で == で比べます。だから Python と Rust の文書は「等しいものは同じハッシュ値を持つ」を、鍵に使う型の要件として書いています。
    約 8 分
  9. 9
    エラーの無視は、どれだけ目立つか
    エラーを戻り値で返す言語でも、例外で投げる言語でも、エラーは無視できます。違うのは、無視するために何を書く必要があり、無視したあとに何が残るかです。
    約 9 分
  10. 10
    寿命と置き場所は別 — 局所変数のアドレスを返すと何が起きるか
    変数をいつまで使ってよいか(寿命)は言語が約束し、スタックとヒープのどちらに置くか(置き場所)は処理系が選びます。
    約 9 分
  11. 11
    回収されることと、閉じられることは別
    GC が約束しているのは「まだ届くものを回収しない」ことまでで、いつ回収するか、そもそも回収するかは約束していません。Python と JavaScript の公式文書はそう書いており、Go の文書はファイナライザについて同じことを書いています。
    約 8 分
  12. 12
    並行処理は、切り替わりうる場所で壊れる
    「読んで・足して・書く」が壊れるのは、読みと書きの間で別の処理に切り替わりうるときです。切り替わりうる場所は言語の並行モデルが決めていて、JavaScript の async と Python の asyncio では await の地点だけ、Go の goroutine ではどこでも、しかも複数のコアで同時にです。
    約 9 分