本書では、 Swift の根幹である Value SemanticsProtocol-oriented Programming に焦点を当て、 Swift とはどのような言語なのかを説明してきました。そのことを、 “はじめに” では

Swift の Heart (中心)となる概念を説明することを通して、 Swift の Heart (心)の形を描き出す

と表現しました。本書を通して描いてきた Heart の形は次のようになります。

Heart の形の本書のまとめ

原点

この図の根底にある、原点とも言えるものが Value Semantics値型 です。


Value Semantics

Value Semantics

本書で最初に取り上げた、すべての大元にあったものが Value Semantics でした。本書のすべての話は、 Value Semantics が大切だということを前提に、 Swift ではどのようにして Value Semantics 中心のコードが実現されているかという話だと言えます。

そのため、まず初めに Value Semantics とは何かを、次に、 Value Semantics を持たない型が引き起こす問題について説明しました。


値型

値型

ミュータブルクラスミュータブル参照型 )は Value Semantics を持たないので、多くの言語では イミュータブルクラスイミュータブル参照型 )を使って Value Semantics が実現されています。しかし、 Swift はその代わりに 値型 を使って Value Semantics を実現します。 値型 を使えば、 イミュータブルクラス と比較して、状態変更を伴うコードを簡潔に記述することができます。

値型 は、 ミュータブルクラス の持つ状態変更の簡潔さと、 イミュータブルクラス の持つ Value Semantics の利点の双方を兼ね備えたものと考えられます。そのような 値型 を使って Value Semantics を実現する、それが本書で説明してきた話の原点でした。


値型中心の世界を実現

値型中心の世界を実現

Heart の図には、 Value Semantics値型 を原点として、二つの軸が描かれています。その一つが、左方向に伸びる 「値型中心の世界を実現」 する軸です。

値型 を使うことで ミュータブルクラスイミュータブルクラス のいいとこ取りができました。しかし、コードのすべてを 値型 で記述するには困難があります。「値型中心の世界を実現」する軸は、そのような困難を乗り越えるために Swift が取り入れた仕組みや提供している機能についての話でした。


値型のコレクション

値型のコレクション

そのような困難の一つがコレクションでした。

コレクションは、その性質から多くの言語で 参照型 として実装されています。コレクションはコードのいたるところで使われるため、コレクションが 参照型 であることは、 値型 だけでコードを書くのが困難であることを意味します。

Swift 標準ライブラリのコレクションは、 Copy-on-Write を用いることで 値型 として実装されています。そのため、 Swift ではコレクションも含めて値型だけでコードが書けることを説明しました。


値型を使いやすくする機能

値型を使いやすくする機能

もう一つの困難は、状態変更に伴うコードを記述する難しさでした。

単純なケースでは、 値型ミュータブルクラス と同じように簡潔なコードで状態変更を扱うことができます。しかし、より複雑なケースでは一筋縄では行かないことがあります。

本書では次の四つを取り上げ、どのようなケースで難しさがあり、それを解決するために Swift がどのような機能を提供しているか、それらを使ってどのように問題を解決するのかを説明しました。

  • 安全な inout 引数
  • mutating func
  • Computed Property を介した変更
  • 高階関数と inout 引数の組み合わせ

値型前提の抽象化を実現

制約としてのプロトコル

Heart の図のもう一つの軸が、上方向に伸びる 「値型前提の抽象化を実現」 する軸です。

冗長なコードの重複を避けるために、抽象化は避けては通れないテーマです。 値型 中心のコードでは、 参照型 中心のコードとは異なる方法でコードを抽象化することを説明しました。


制約としてのプロトコル

制約としてのプロトコル

オブジェクト指向プログラミングObject-oriented Programming )においては、 継承 を元にした サブタイプポリモーフィズムサブタイピング )が抽象化における重要な役割を果たします。しかし、 値型継承 することができません。そこで、 Swift ではプロトコルを用いてコードを抽象化します。

このとき、 値型 中心の Swift では サブタイプポリモーフィズム よりも パラメトリックポリモーフィズム が適していると説明しました。これをプロトコルに焦点を当てて言い換えると、 Swift ではプロトコルを型として用いるよりも、制約として用いるのが適していると言えます。 Swift の標準ライブリでも制約としてのプロトコルが広く使われています。

Protocol-oriented Programming には明確な定義がないですが、本書ではそのようなプロトコルの使われ方に焦点を当てて Protocol-oriented Programming を説明しました。


戻り値の型の抽象化

戻り値の型の抽象化

パラメトリックポリモーフィズム による抽象化を実現するために ジェネリクス が用いられますが、 ジェネリクス は戻り値の型をうまく抽象化することができません。そのため、 ジェネリクス と対になる概念として、戻り値の型を抽象化する リバースジェネリクス が考案されました。さらに、 リバースジェネリクス を簡潔に記述するための構文として Opaque Result Type が提案されました。


引数の型の抽象化

引数の型の抽象化

Opaque Result Type は戻り値の型についてのものでしたが、同じことを引数の型についても考えることができます。それが、 ジェネリクス を簡潔に記述するための構文 Opaque Argument Type でした。


Opaque Type と Existential Type

Opaque Type と Existential Type

Opaque Argument TypeOpaque Result Type をまとめて Opaque Type と呼びますが、 Opaque Type はプロトコルを制約として用います。これの対になるものに Existential Type があり、 Existential Type はプロトコルを型として用います。

Opaque Type には someExistential Type には any というキーワードを修飾子として用いることで、「制約として」・「型として」のプロトコルの違いを明確にすることができました。


まとめ

このように、本書は Value Semantics値型 を原点に、「値型中心の世界」と「値型前提の抽象化」の実現という二つの軸で、 Swift という言語の Heart を説明してきました。

Swift は決して難解な言語ではないですが、 参照型 中心の言語が多い中では、 値型 を中心とした特徴的な言語だと言えます。言語を使いこなすには、その言語独自の考え方を理解することが欠かせません。

本書が Swift という言語を理解する手助けになったなら幸いです。