Swift Digest
SE-0483 | Swift Evolution

InlineArray型糖衣構文

InlineArray Type Sugar

Proposal
SE-0483
Authors
Hamish Knight, Ben Cohen
Review Manager
Holly Borla
Status
Implemented (Swift 6.2)

このダイジェストはClaude Opus 4.7 / 4.8によって生成されたものです(License)。原文はこちら

01 何が問題だったのか

SE-0453 で導入された InlineArray は、要素数を型パラメータに含む固定長配列です。ヒープアロケーションを伴わず、要素をインラインに保持するため、パフォーマンスが重要な場面で Array の代替となります。

しかし、通常の Array[Int] という糖衣構文を持つのに対し、InlineArray には糖衣構文がなく、次のように型名を直接書く必要がありました。

let fiveIntegers: InlineArray<5, Int> = .init(repeating: 99)

これは Array[Int] と比べて記述が冗長で、特に多次元になると顕著に読みづらくなります。

let fiveByFive: InlineArray<5, InlineArray<5, Int>> = .init(repeating: .init(repeating: 99))

Array を使うべき」という印象を与えてしまう

C・C++・Rust・Go・Java など、Swift と同じカテゴリの多くの言語は固定長配列に簡潔な構文を与えています。Swift では逆に、動的配列である Array にだけ糖衣構文があり、固定長の InlineArray は冗長な型名のままでした。

この非対称性は、「Array こそが第一候補で、InlineArray はごく稀なマイクロ最適化である」という誤った印象を読者に与えます。実際には、3次元ベクトルのように要素数が静的に決まる値を [Double] で表すと、ヒープアロケーション、BitwiseCopyable ではなくなること、境界チェックや一意性チェックなど、避けられたはずのパフォーマンス上の不利を負うことになります。InlineArrayArray は性能特性の異なる対等な選択肢であり、どちらも同じように扱いやすい糖衣構文を備えているべきでした。

02 どのように解決されるのか

InlineArray に対して、サイズと要素型を of で区切る糖衣構文 [サイズ of 要素型] を導入します。

// 従来
let fiveIntegers: InlineArray<5, Int> = .init(repeating: 99)

// 新しい糖衣構文
let fiveIntegers: [5 of Int] = .init(repeating: 99)

of は “an array of five ints”(5個の Int の配列)という英語の自然なフレーズに近い読み方ができ、inlet と同じように短い文脈依存のキーワードとして機能します。

使い方

糖衣構文は InlineArray と完全に等価なので、ネストや型推論、右辺での利用など、元の型が書ける場所ならどこでも使えます。

// ネスト
let fiveByFive: [5 of [5 of Int]] = .init(repeating: .init(repeating: 99))

// 文脈からの型推論(サイズや要素型に _ を使える)
let fiveIntegers: [5 of _] = .init(repeating: 99)
let fourBytes: [_ of Int8] = [1, 2, 3, 4]
let fourIntegers: [_ of _] = [1, 2, 3, 4]

// 右辺での利用
let fiveDoubles = [5 of _](repeating: 1.23)

// 型として使える場所すべて
[5 of Int](repeating: 99)
MemoryLayout<[5 of Int]>.size
unsafeBitCast((1, 2, 3), to: [3 of Int].self)

サイズの位置に書けるのは、現状の InlineArray の仕様に沿って整数リテラルまたは整数型パラメータに限られます。将来 InlineArray 側で任意の式が許されるようになれば、この糖衣構文も同様に拡張される想定です。

記法上のルール

  • of の前後には空白が必要です。[5of Int] は書けません。
  • 空白の数は揃える必要はありません。[5 of Int] のように片側だけ多くても構いません。
  • of の後ろには改行を置けますが、前に置くことはできません。これは文法上曖昧にはならないものの、パーサのエラー回復がしやすくなるように意図された制約です。

of を選んだ理由

セパレータの候補としては x*;・区切り記号なし、などが検討されました。of が選ばれたのは主に次の理由からです。

  • 将来、式をサイズに書けるようになったとき、[5 * N * Int]* 演算子と紛らわしくなるのに対し、[5 * N of Int] は明確に読めます。
  • 将来、値版の糖衣構文(後述)が導入されたとき、[5 of 5] は「5個の5」と自然に読めますが、[5 x 5][5 * 5] は掛け算と混同されます。
  • 完全推論した [_ of _] が、[_ x _][_ * _] と比べて ASCII アート感が少なく視認しやすいです。

03 今後の見通し

値側への of の展開

同じ of を値リテラル側にも展開する方向性が示されています。型側だけでなく、サイズと値からなるリテラルとして書けるようにする構想です。

// 型が [5 of Int] に推論される
let fiveInts = [5 of 99]

// 型が [5 of [5 of Int]] に推論される
let fiveByFive = [5 of [5 of 99]]

このリテラルは InlineArray だけでなく既存の型にも適用できる想定で、たとえば Array に対しては .init(repeating: 99, count: 5) と等価な書き方として使えるようになります。

// .init(repeating: 99, count: 5) と等価
let dynamic: [Int] = [5 of 99]

ただし、これは新たな expressible-by-literal プロトコルや、リテラルからイニシャライザへの対応付けの仕組みなどを必要とする大きな設計上の課題を含むため、別 Proposal に委ねられています。型側の糖衣構文として of が選ばれたのは、この値側への拡張も見据えてのことですが、実現が約束されているわけではありません。

多次元配列のフラット表記

[5 of [5 of Int]] のような多次元の表記を、[5 of 5 of Int] のようにフラットに書けるようにする拡張も検討対象として挙げられています。後から追加で導入できる糖衣として位置づけられており、こちらも将来の方向性であって実現が保証されているわけではありません。