列挙型 (Enum)

値が有限個のバリアントのいずれかであることを表す型。言語ごとに表現力が大きく異なり、単なる名前付き整数定数から、データ付きバリアント(= tagged union = 直和型)まで連続的なスペクトラムを持つ。

進化のスペクトラム

C enum              → 名前付き整数定数。型安全性なし
    ↓
Java enum           → クラスベース。フィールド・メソッド付き
    ↓
Swift enum          → Associated Value(データ付きバリアント)
    ↓
Rust enum           → データ付きバリアント + パターンマッチ + ジェネリクス = 完全な tagged union
Haskell data        → 同上(ADT の直和部分)
Almide type ... |   → 同上

言語別比較

C enum — 名前付き整数

enum Color { RED, GREEN, BLUE };  // RED=0, GREEN=1, BLUE=2

enum Color c = RED;
c = 42;  // コンパイル通る。型安全性なし

C++ enum class — スコープ付き整数

enum class Color { Red, Green, Blue };

Color c = Color::Red;
// c = 42;  // コンパイルエラー(型安全)
// int n = c;  // 暗黙変換も禁止

Java enum — クラスベース

enum Planet {
    MERCURY(3.303e+23, 2.4397e6),
    VENUS(4.869e+24, 6.0518e6),
    EARTH(5.976e+24, 6.37814e6);

    private final double mass;
    private final double radius;

    Planet(double mass, double radius) {
        this.mass = mass;
        this.radius = radius;
    }

    double surfaceGravity() {
        return 6.67300E-11 * mass / (radius * radius);
    }
}

TypeScript enum — コンパイル時定数

enum Direction {
    Up = "UP",
    Down = "DOWN",
    Left = "LEFT",
    Right = "RIGHT",
}

// const enum なら完全にインライン化(ランタイムコストゼロ)
const enum Status { Active, Inactive }

Python Enum — クラスベース

from enum import Enum, auto

class Color(Enum):
    RED = auto()
    GREEN = auto()
    BLUE = auto()

# イテレーション可能
for c in Color:
    print(c)

Rust enum — 完全な tagged union

enum Shape {
    Circle(f64),                      // タプルバリアント
    Rect { width: f64, height: f64 }, // 構造体バリアント
    Point,                            // ユニットバリアント
}

fn area(s: &Shape) -> f64 {
    match s {
        Shape::Circle(r) => std::f64::consts::PI * r * r,
        Shape::Rect { width, height } => width * height,
        Shape::Point => 0.0,
    }
}

Haskell data — ADT の直和

data Shape
    = Circle Double
    | Rect Double Double
    | Point

area :: Shape -> Double
area (Circle r)   = pi * r * r
area (Rect w h)   = w * h
area Point        = 0

Almide type — One Canonical Form

type Shape =
  | Circle(Float)
  | Rect{ w: Float, h: Float }
  | Point

fn area(s: Shape) -> Float =
  match s {
    Circle(r) => 3.14159 * r * r
    Rect{ w, h } => w * h
    Point => 0.0
  }

Swift enum — Associated Value

enum Barcode {
    case upc(Int, Int, Int, Int)
    case qrCode(String)
}

let code = Barcode.qrCode("ABCDEF")
switch code {
    case .upc(let ns, let m, let p, let c):
        print("UPC: \(ns)-\(m)-\(p)-\(c)")
    case .qrCode(let value):
        print("QR: \(value)")
}

表現力の比較表

言語データ付きバリアント別データ型パターンマッチ網羅性チェックジェネリクス
C enumxxx警告のみx
C++ enum classxxx警告のみx
Java enum共通フィールドのみxswitch非網羅でも可x
Python Enumxxmatch (3.10+)xx
TypeScript enumxxswitchxx
Swift enumooswitchoo
Rust enumoomatchoo
Haskell dataooパターンマッチoo
Almide typeoomatchoo

下段の 4 言語は tagged union(= 直和型) として完全な表現力を持つ。上段は本質的に名前付き定数。

標準ライブラリにおける活用

Rust / Haskell / Almide で enum(直和型)は言語の中核的パターンとして多用される:

型役割言語
Option<T> / Maybe a / Option[T]値の有無(null の型安全な代替)Rust / Haskell / Almide
Result<T, E> / Either a b / Result[T, E]成功/失敗(例外の型安全な代替)Rust / Haskell / Almide
Ordering比較結果(Less / Equal / Greater)Rust / Haskell / Almide
Cow<'a, T>借用 or 所有の遅延決定Rust

これらはすべて enum(直和型)で定義されている。

C enum との断絶

C enum と Rust/Haskell/Almide の enum は名前が同じだけの別概念と考えたほうが正確:

多くの言語はこの 2 つの中間のどこかに位置する。

押さえどころ(カード化候補)

関連

Graph