Swift Standard Library相関図を作ってみた・眺めてみた #swtws

この記事は[Swift Tweets 2017 Spring - connpass](https://swift-tweets.connpass.com/event/48887/)にて「Swift Standard Library相関図」というタイトルで発表したものにたくさん加筆したり修正したものです。

3〜4個くらいのProtocol同士の継承関係のツリーなら各所の発表でよく見るのですが、どういうわけか全体図を見たことがないので作ることにしました。

# Swift Standard Libraryとは

> The Swift standard library defines a base layer of functionality for writing Swift programs

`import Foundation` しなくてもSwiftが素で使えるシンボルたち。
ドキュメントは [Swift Standard Library | Apple Developer Documentation](https://developer.apple.com/reference/swift/)
実装は [swift/stdlib/public/core at master · apple/swift](https://github.com/apple/swift/tree/master/stdlib/public/core)

公式ドキュメントにある各シンボルのページについて、以下の点については注意が必要である。

__Protocol → Protocol の継承関係が被継承側のページには書かれていない__

Structure → Protocolの関係は継承側のConforms Toと被継承側のAdopted Byの両方のページに書かれている。Protocol → Protocolも継承側のInherits fromに書かれている。被継承側のAdopted Byには書かれていない。
struct [Int](https://developer.apple.com/reference/swift/int) → protocol [SignedInteger](https://developer.apple.com/reference/swift/signedinteger) → protocol [Integer](https://developer.apple.com/reference/swift/integer) → protocol [Strideable](https://developer.apple.com/reference/swift/strideable) → protocol [Comparable](https://developer.apple.com/reference/swift/comparable) あたりを見るとこの現象がわかりやすい。

__全ての継承関係が書かれていない(?)__

読み間違えかと思ったが、Relationshipsの欄のConforms To/Inherits From/From Protocol等を全部合わせてもやっぱり何か足りない(後で紹介する`UnsafeRawBufferPointer.Iterator` など)。理由があるのか？誰か知っていたら教えてください。

あとはシンボル名に `<wbr>` が混じっていることに気がつかなくてグラフ作成時に意図した挙動にならず悩んだとかそのくらい。

# 完成図

とても重たくて載せられないので、ここにはdot言語へのリンクと超縮小図のみ載せる。
公式ドキュメントを愚直にスクレイピングして作ったので先述の「公式がちゃんと網羅していない」問題に思い切り引っかかり、__正確な図ではない__。

https://gist.github.com/S-Shimotori/df20cc0e7c0ee0c1dc64a6e35045ecb0

`brew install graphviz` して `dot` コマンドを正しく叩くと出力される。

<img width="1280" alt="2fixed.png" src="https://qiita-image-store.s3.amazonaws.com/0/84589/4e2e9ff6-ba33-0155-625b-9758806a1a58.png">

青ノードがEnumeration、緑ノードがClass、灰ノードがProtocol、赤ノードがStructureのシンボルを指す。

見やすくするため、
`Custom(Debug)?StringConvertible` / `CustomPlaygroundQuickLookable` / `Expressible.+` のノードとそこへ向かうエッジは掲載していない。
`Equatable` / `Comparable` / `Hashable` / `CustomReflectable` へのエッジを薄くした。
Protocol間のエッジを太くした。
継承関係を持つProtocolのノードを大きくした。

# 眺めてみる

## Structure / Class / Enumeration / Protocol

Structureは140個、Classは1個、Enumerationは12個、Protocolは48個ある。もちろん今回の主役はProtocolである。
ClassとEnumerationは数が少ないので、せっかくなので列挙してみる。

Class:

* [ManagedBuffer](https://developer.apple.com/reference/swift/managedbuffer)

Enumeration:

* [CommandLine](https://developer.apple.com/reference/swift/commandline)*
* [FloatingPointClassification](https://developer.apple.com/reference/swift/floatingpointclassification)
* [FloatingPointRoundingRule](https://developer.apple.com/reference/swift/floatingpointroundingrule)
* [FloatingPointSign](https://developer.apple.com/reference/swift/floatingpointsign)
* [ImplicitlyUnwrappedOptional](https://developer.apple.com/reference/swift/implicitlyunwrappedoptional)
* [MemoryLayout](https://developer.apple.com/reference/swift/memorylayout)*
* [Mirror.AncestorRepresentation](https://developer.apple.com/reference/swift/mirror.ancestorrepresentation)
* [Mirror.DisplayStyle](https://developer.apple.com/reference/swift/mirror.displaystyle)
* [Never](https://developer.apple.com/reference/swift/never)*
* [Optional](https://developer.apple.com/reference/swift/optional)
* [PlaygroundQuickLook](https://developer.apple.com/reference/swift/playgroundquicklook)
* [UnicodeDecodingResult](https://developer.apple.com/reference/swift/unicodedecodingresult)

これ以外はStructureかProtocolと覚えておけばよい。Enumには `Optional` ( `.none` / `.some` )のようにちゃんと列挙しているものと、 `Never` のように我々がインスタンスを取るようなものではないもの(*で印をつけたもの)が混ざっている。

## [Equatable](https://developer.apple.com/reference/swift/equatable) / [Comparable](https://developer.apple.com/reference/swift/comparable)

おなじみ `Equatable` / `Comaparable` 。あちこちから継承されている。
位置としてはここ。
<img width="1280" alt="3.png" src="https://qiita-image-store.s3.amazonaws.com/0/84589/8ccbb674-ab79-a741-532a-ff857d62ee12.png">

StrideableやSequenceのツリーを綺麗に出すために犠牲になってもらったのでノードが遠くなった。

## [Collection](https://developer.apple.com/reference/swift/collection) / [Sequence](https://developer.apple.com/reference/swift/sequence)

`Sequence` を頂点とするツリー。 [IteratorProtocol](https://developer.apple.com/reference/swift/iteratorprotocol) 自体は `Sequence` ツリーの一員ではないが、各Iterator が `Sequence` を実装している。

<img width="1280" alt="4.png" src="https://qiita-image-store.s3.amazonaws.com/0/84589/6cda9bc5-31dc-41bd-ae19-f8370dc8cf2f.png">

## [Strideable](https://developer.apple.com/reference/swift/strideable)

`Comparable` な連続する値を指す。UnsafePointer群と整数と浮動小数が連なる。

<img width="806" alt="5.png" src="https://qiita-image-store.s3.amazonaws.com/0/84589/21a0bf73-f9ac-66ad-80cd-f9db6b6b029b.png">

## [CVarArg](https://developer.apple.com/reference/swift/cvararg)

C言語の可変長引数で扱える型を指す。公式ドキュメントのページのAdopted ByにはFoundationやナントカKit所属のシンボルが無数に並んでいる。
SSL内では

* [Array](https://developer.apple.com/reference/swift/array)
* [AutoReleasingUnsafeMutablePointer](https://developer.apple.com/reference/swift/autoreleasingunsafemutablepointer)
* [Dictionary](https://developer.apple.com/reference/swift/dictionary)
* [Int](https://developer.apple.com/reference/swift/int) / [Int64](https://developer.apple.com/reference/swift/int64) / [Int32](https://developer.apple.com/reference/swift/int32) / [Int16](https://developer.apple.com/reference/swift/int16) / [Int8](https://developer.apple.com/reference/swift/int8)
* [OpaquePointer](https://developer.apple.com/reference/swift/opaquepointer)
* [Set](https://developer.apple.com/reference/swift/set)
* [String](https://developer.apple.com/reference/swift/string)
* [UInt](https://developer.apple.com/reference/swift/uint) / [UInt64](https://developer.apple.com/reference/swift/uint64) / [UInt32](https://developer.apple.com/reference/swift/uint32) / [UInt16](https://developer.apple.com/reference/swift/uint16) / [UInt8](https://developer.apple.com/reference/swift/uint8)
* [UnsafeMutablePointer](https://developer.apple.com/reference/swift/unsafemutablepointer)
* [UnsafePointer](https://developer.apple.com/reference/swift/unsafepointer)

のみ。

## Pointer

各Pointerはそれぞれ役割が異なる。よってくっついているProtocolも異なる。
`AutoreleasingUnsafeMutablePointer` や[CVaListPointer](https://developer.apple.com/reference/swift/cvalistpointer)、`OpaquePointer`はObjCやC関係のポインタである。[ManagedBufferPointer](https://developer.apple.com/reference/swift/managedbufferpointer)は名の通り連続領域にアクセスするためのもの。

UnsafePointerについてはProtocolツリーの観点から2種類に分けられる。 `Strideable` なUnsafePointerと `Collection` なUnsafePointerである。

### `Strideable` なUnsafePointer

* `UnsafePointer`
* [UnsafeMutablePointer](https://developer.apple.com/reference/swift/unsafemutablepointer)
* [UnsafeRawPointer](https://developer.apple.com/reference/swift/unsaferawpointer)
* [UnsafeMutableRawPointer](https://developer.apple.com/reference/swift/unsafemutablerawpointer)

### `Collection` なUnsafePointer

* [UnsafeBufferPointer](https://developer.apple.com/reference/swift/unsafebufferpointer)
* [UnsafeMutableBufferPointer](https://developer.apple.com/reference/swift/unsafemutablebufferpointer)
* [UnsafeMutableRawBufferPointer](https://developer.apple.com/reference/swift/unsafemutablerawbufferpointer)
* [UnsafeRawBufferPointer](https://developer.apple.com/reference/swift/unsaferawbufferpointer)

Buffer、つまりこちらは連続領域を指す。

## 孤立しているシンボル

Unicodeのデコード/エンコードは他から独立している。

* protocol [UnicodeCodec](https://developer.apple.com/reference/swift/unicodecodec) / struct [UTF-8](https://developer.apple.com/reference/swift/utf8) / struct [UTF-16](https://developer.apple.com/reference/swift/utf16) / struct [UTF-32](https://developer.apple.com/reference/swift/utf32)

以下は(少なくともSSL内では)完全に継承関係を持たないもの。

* [MirrorPath](https://developer.apple.com/reference/swift/mirrorpath)
* [Error](https://developer.apple.com/reference/swift/error): [NSError](https://developer.apple.com/reference/foundation/nserror)(Foundation)と[CFError](https://developer.apple.com/reference/corefoundation/cferror)(CoreFoundation)から継承されている
* [AnyObject](https://developer.apple.com/reference/swift/anyobject)
* `PlaygroundQuickLook`
* `Never`
* `Mirror.DisplayStyle`
* `Mirror.AncestorRepresentation`
* `MemoryLayout`
* `FloatingPointSign`
* `FloatingPointRoundingRule`
* `FloatingPointClassification`
* `CommandLine`
* `ManagedBuffer`
* [Unmanaged](https://developer.apple.com/reference/swift/unmanaged)

なお、ドキュメント上Conforms Toの欄がないことになっている以下のシンボルについては、実際はちゃんと継承している模様。

* [UnsafeRawBufferPointer.Iterator](https://developer.apple.com/reference/swift/unsaferawbufferpointer.iterator) / [UnsafeMutableRawBufferPointer.Iterator](https://developer.apple.com/reference/swift/unsafemutablerawbufferpointer.iterator)([swift/UnsafeRawBufferPointer.swift.gyb at master · apple/swift](https://github.com/apple/swift/blob/master/stdlib/public/core/UnsafeRawBufferPointer.swift.gyb#L109)): `IteratorProtocol`, `Sequence`
* [String.UnicodeScalarView.Iterator](https://developer.apple.com/reference/swift/string.unicodescalarview.iterator)([swift/StringUnicodeScalarView.swift at master · apple/swift](https://github.com/apple/swift/blob/master/stdlib/public/core/StringUnicodeScalarView.swift#L216)): `IteratorProtocol`
* [String.UTF16View.Indices](https://developer.apple.com/reference/swift/string.utf16view.indices)
([swift/StringUTF16.swift at master · apple/swift](https://github.com/apple/swift/blob/master/stdlib/public/core/StringUTF16.swift#L560)): `BidirectionalCollection`

## 今回省略したシンボル

グラフを描くにあたり犠牲になったのは以下。

* [ExpressibleByArrayLiteral](https://developer.apple.com/reference/swift/expressiblebyarrayliteral) / [ExpressibleByBooleanLiteral](https://developer.apple.com/reference/swift/expressiblebybooleanliteral) / [ExpressibleByDictionaryLiteral](https://developer.apple.com/reference/swift/expressiblebydictionaryliteral) / [ExpressibleByExtendedGraphemeClusterLiteral](https://developer.apple.com/reference/swift/expressiblebyextendedgraphemeclusterliteral) / [ExpressibleByFloatLiteral](https://developer.apple.com/reference/swift/expressiblebyfloatliteral) / [ExpressibleByIntegerLiteral](https://developer.apple.com/reference/swift/expressiblebyintegerliteral) / [ExpressibleByNilLiteral](https://developer.apple.com/reference/swift/expressiblebynilliteral) / [ExpressibleByStringLiteral](https://developer.apple.com/reference/swift/expressiblebystringliteral) / [ExpressibleByUnicodeScalarLiteral](https://developer.apple.com/reference/swift/expressiblebyunicodescalarliteral)
* [CustomStringConvertible](https://developer.apple.com/reference/swift/customstringconvertible) / [CustomDebugStringConvertible](https://developer.apple.com/reference/swift/customdebugstringconvertible)
* [CustomPlaygroundQuickLookable](https://developer.apple.com/reference/swift/CustomPlaygroundQuickLookable)

`ExpressibleBy.+Literal`はナントカ型で対象の型をイニシャライザできることを示す。`Custom(Debug)?StringConvertible` と `CustomPlaygroundQuickLookable` はそれぞれデバッグ用に便利なプロパティをつけるもの。

# まとめ

公式ドキュメントに書いてあることが全部ではない。