# 機能設計書 86-filter_nulls

## 概要

本ドキュメントは、Hack Standard Library (HSL) の Dict モジュールにおける `filter_nulls` 関数の機能設計を記述する。この関数は、null 以外の値を持つエントリのみを含む新しい dict を返す機能を提供する。重要な特徴として、型システムレベルで null が除去されることを保証する。

### 本機能の処理概要

**業務上の目的・背景**：Hack 言語は強力な型システムを持ち、nullable 型（?T）と non-nullable 型（T）を厳密に区別する。データ処理において、nullable な値を含むコレクションから null を除去し、non-nullable な型のコレクションを得たいケースは非常に多い。例えば、データベースから取得したデータで null が含まれる可能性がある場合や、外部 API からのレスポンスで optional なフィールドがある場合などである。本関数は、このような null 除去を型安全に行い、型チェッカーに null が除去されたことを認識させることができる。

**機能の利用シーン**：
- nullable な値を含む dict から null を除去する場合
- 型チェッカーに null が除去されたことを認識させたい場合
- Optional なデータを必須データとして後続処理に渡す場合
- データクレンジング処理で null を除外する場合

**主要な処理内容**：
1. 入力の KeyedTraversable を順次イテレート
2. 各値が null でないかをチェック（`!== null`）
3. null でない場合のみ、結果の dict にエントリを追加
4. 結果の dict を返却（型は `dict<Tk, Tv>` で、null を含まない）

**関連システム・外部連携**：本関数は純粋な計算処理であり、外部システムとの連携はない。

**権限による制御**：本関数は汎用ユーティリティであり、権限による制御は行わない。

## 関連画面

| 画面No | 画面名 | 関連種別 | 関連する操作・処理 |
|--------|--------|----------|------------------|
| - | 該当なし | - | 本プロジェクトはUIを持たないライブラリのため画面なし |

## 機能種別

計算処理（フィルタリング・型変換）

## 入力仕様

### 入力パラメータ

| パラメータ名 | 型 | 必須 | 説明 | バリデーション |
|-------------|-----|-----|------|---------------|
| $traversable | KeyedTraversable<Tk, ?Tv> | Yes | nullable な値を含む可能性がある KeyedTraversable | なし |

### 入力データソース

関数引数として直接渡される KeyedTraversable オブジェクト。

## 出力仕様

### 出力データ

| 項目名 | 型 | 説明 |
|--------|-----|------|
| 戻り値 | dict<Tk, Tv> | null を含まない値のみのエントリを含む dict（型レベルで non-nullable が保証される） |

### 出力先

関数の戻り値として呼び出し元に返却。

## 処理フロー

### 処理シーケンス

```
1. 結果用の空 dict を初期化
2. $traversable を foreach でイテレート
   ├─ 各値が null でないかをチェック（!== null）
   └─ null でない場合、結果 dict にエントリを追加
3. 結果の dict を返却
```

### フローチャート

```mermaid
flowchart TD
    A[開始] --> B[result = dict[]]
    B --> C{次のエントリがあるか?}
    C -->|No| D[result を返却]
    C -->|Yes| E{value !== null か?}
    E -->|Yes| F[result にエントリを追加]
    E -->|No| C
    F --> C
    D --> G[終了]
```

## ビジネスルール

### 業務ルール

| ルールNo | ルール名 | 内容 | 適用条件 |
|---------|---------|------|---------|
| BR-86-01 | 厳密な null チェック | 値が厳密に null である場合のみ除外（`!== null`） | 常時 |
| BR-86-02 | falsy 値の保持 | false、0、空文字列などの falsy な値は保持される | 常時 |
| BR-86-03 | 型の変換 | 入力 `?Tv` から出力 `Tv` へ型が変換される | 常時 |
| BR-86-04 | 元の順序保持 | 結果の dict は元の順序を保持する | 常時 |

### 計算ロジック

フィルタリング処理:
- 結果 = { (k, v) | (k, v) in $traversable AND v !== null }

## データベース操作仕様

### 操作別データベース影響一覧

本関数はデータベース操作を行わない。

## エラー処理

### エラーケース一覧

| エラーコード | エラー種別 | 発生条件 | 対処方法 |
|------------|----------|---------|---------|
| - | 型エラー | 不正な型の引数が渡された場合 | Hack型システムによりコンパイル時に検出 |

### リトライ仕様

本関数は純粋関数であり、リトライの概念は適用されない。

## トランザクション仕様

本関数はステートレスな純粋関数であり、トランザクション管理は不要。

## パフォーマンス要件

- 時間計算量: O(n)
- 空間計算量: O(n)

## セキュリティ考慮事項

- 純粋関数であり、副作用がないためセキュリティリスクは低い
- 入力データの検証は呼び出し元の責任

## 備考

- `Dict\filter()` を述語なしで使用すると falsy な値も除外されるため、null のみを除外したい場合は必ず `filter_nulls()` を使用すること
- 型チェッカーが null 除去を認識するため、後続の処理で null チェックが不要になる
- Vec および Keyset モジュールにも同名の関数が存在する

---

## コードリーディングガイド

本機能を理解するために参照すべきファイルと、推奨する読み解き順序を以下に示す。

### 推奨読解順序

#### Step 1: データ構造を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 1-1 | select.php | `src/dict/select.php` | filter_nulls 関数のシグネチャと型パラメータ |

**読解のコツ**: `KeyedTraversable<Tk, ?Tv>` の `?Tv` は nullable 型を表す。戻り値の `dict<Tk, Tv>` は non-nullable。

#### Step 2: エントリーポイントを理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 2-1 | select.php | `src/dict/select.php` | filter_nulls 関数の実装（145-155行目） |

**主要処理フロー**:
1. **145-147行目**: 関数シグネチャ - 入力は `?Tv`、出力は `Tv`
2. **148行目**: 結果 dict の初期化
3. **149-153行目**: foreach ループで null チェックと追加
4. **154行目**: 結果を返却

#### Step 3: 関連関数を理解する

| 順序 | ファイル | パス | 読解ポイント |
|-----|---------|------|-------------|
| 3-1 | select.php | `src/dict/select.php` | filter（79-91行目）- 述語ベースのフィルタ |

**比較ポイント**:
- `filter()` は述語なしで呼ぶと boolval を使用し、falsy な値も除外
- `filter_nulls()` は厳密に null のみを除外し、falsy な値は保持

### プログラム呼び出し階層図

```
Dict\filter_nulls($traversable)
    |
    +-- foreach ($traversable as $key => $value)
            |
            +-- if ($value !== null)  [厳密な null チェック]
            |
            +-- $result[$key] = $value  [条件付きで追加]
```

### データフロー図

```
[入力]                           [処理]                        [出力]

$traversable ──────────────> foreach ループ ───────────> dict<Tk, Tv>
(KeyedTraversable<Tk, ?Tv>)      |                       (non-nullable)
                                 +-- value !== null: 追加
                                 +-- value === null: スキップ

型の変換:
  ?Tv (nullable) ──────────> Tv (non-nullable)
```

### 関連ファイル一覧

| ファイル | パス | 種別 | 役割 |
|---------|------|------|------|
| select.php | `src/dict/select.php` | ソース | filter_nulls 関数の実装 |
| DictSelectTest.php | `tests/dict/DictSelectTest.php` | テスト | filter_nulls のユニットテスト（278-334行目） |
