Swift Protocols and Generics: 文章索引,簡介與資源

文章索引

  1. Protocol 和其他 Type 有什麼不一樣?
  2. Protocol as Type 和 Type Erasure 有什麼關係?
  3. Any Protocol 和 Some Protocol 有何異同?
  4. Protocol as Type 的限制,新舊版的 Swift 有什麼不一樣?
  5. Protocol as Type 和 Generics 間如何抉擇?

簡介

這個系列是寫在 Swift 5.6 後,SE-0335 (Introduce existential any) 剛實作,SE-0309 (Unlock existentials for all protocols) 也將到來的時期。

在這一系列的文章裡,我想主要從學習、深化理解的角度,從基本概念來探索 Swift 的 protocol existentials 和 generics。

Protocol existentials 和 generics 分別來看都是很大的題目,它們之間的關係也十分密切。兩者共通之處,無疑就在於它們都是關於 polymorphism — 多型。(程式相關的英文名詞對我來說比較能快速理解,所以寫作時會中英夾雜,請讀者見諒。)

只要是寫 iOS 的開發者,打從一開始寫 app 就會頻繁接觸到它們。舉例來說:

  • 最基本的 Array 就是一個 generic struct
  • SwiftUI 的 View 是一個 protocol with associated type
  • 實作 View body 時的 return type 會用到 opaque result type,類似一種「反向 generic」

不過,平常如果只是要用別人寫好的 protocols 或 generics,我們也不太需要理解得非常透澈。只要記得一些基本規則、模式,知道常見錯誤的解決方法就好了。直到我們開始好奇某些現象的根本原因,或是開始用更複雜的組合、創造自己的使用方式,才開始需要對 Swift 的 type system 的設計有更深一層的理解。

在這學習進階使用的階段,開發者容易遇到的一個困難,在於如何判斷何時該使用 generics,何時該使用 protocol existentials。Swift 近年來在 generics & protocol 方面的演變,很大一部份就環繞在讓功能更完整、語法更自然,來引導開發者使用這些進階功能。但這些功能本身就含有複雜的概念,所以就算語法再怎麼清楚,仍是要靠開發者自己去搞懂很多事情。

這系列文章主要的目的,就是想為了在這個階段的開發者朋友們,提供多一個資源來建構一些基礎理解,以利之後的學習與應用。

其實,任何人只要有心,就可以在網上找到許多相關資源。有的是正式文件,有的是前輩專家寫的解說,足以解答任何你可能有的疑問。底下,我也提供了我的參考資料。那麼,我幹嘛還要自己寫這些文章呢?

寫作方向

一般這類主題的文章,作者會著重於如何做最清楚、易懂的解釋。這個系列的主要不同,是想在建構理解方面,多提供讀者們一些引導。建構理解是一件苦差事,我們不僅要吸收新知,還要透過反覆思考,在腦中連結多方資訊,內化為有結構的知識。光是看懂解釋是不夠的。

因此,在每個主題之前,我會試著點出一個「essential question」(核心問題)。理想上,一個 essential question 是開放性的問題,並沒有標準答案。隨著回答者的經驗和理解程度不同,essential question 也有著不同深度、廣度的回答方式。所以,它們的目的是幫讀者「定位」文章的主題,但不是完全只對應文章本身。

另外,我試著把每個主題塑造成兩個觀念的對比。藉由比較它們的異同,來幫助連結不同的觀念。我也希望讀者們,能不侷限於我有提到的問題和對比,而能自己提出新的問題、做延伸的對比,來進一步對這些主題有更全盤的認識。

以上參考了學習科學裡的兩個原則:Self-explanation 及 contrasting cases。如果讀者想要確實從這個系列有所收穫,請務必自己試著回答問題、比對異同。

閱讀建議

如上所說,複雜概念的理解,是要由自己建構起來的。因此我建議讀者們把這些文章當成思辨的引導,而非單純被動的閱讀。

  1. Essential question(核心問題)
    • 向你的黃色小鴨,同事,或空氣中隱形的面試官回答這個問題。
    • 同時,試著預測文章接下來要講什麼?
  2. 內文
    • 看到文中拋出問題時,先自己試答。
    • 讀完一個段落,停下來做個評估,他講得對嗎?和我的認知有沒有不同?
  3. 總結
    • 重新回答一開始的 essential question。
    • 回思、比對你讀前的答案,讀後的答案,和文章中呈現的內容。

參考資源

下面有一些我覺得相當值得參考的網路資源。每個連結下面我會列出在文章裡相關的內容主題。如果覺得我寫得不夠深入,這裡有更詳盡的資料可以參考。(可想而知,這原本是我自己的參考筆記。)

Swift Evolution

SE-0309 Unlock existentials for all protocols

Unlock existentials for all protocols, moving the restrictions to individual
members. Covariant associated types are type-erased to the upperbound.
Improved diagnostics. Also discusses value-level abstraction (existentials)
vs. type-level abstraction (generics).

SE-0335 Introduce existential any

Existential any, rationale and detailed design. Discusse how there’s no
obvious way to have an existential type for PATs, with an example. Existential
types are expensive, yet have minimal spelling that hides all the cost.

SE-0244 Opaque Result Types

Framing this feature as “type-level abstraction for returns”. Opaque types used by the likes of SwiftUI is straight-forward in terms of usage, but the full design has lots of detailed concerns.

SE-0341 Opaque Parameter Declarations

TBD

Swift Forum: Improving the UI of generics

Follow-up to the Generics Manifesto. Explaining type-level and value-level abstraction, i.e. existentials and generics. Limitations of value-level abstraction (existentials), like can’t do Comparable, and that existentials can never reach full power of generics. Opaque return type as “reverse generics”, filling the void of having type-level abstraction for function’s returns. Improving notations, “angle bracket blindness” and expressing constraints. Clarifying existential types: protocol as a constraint vs. protocol as a type, confusion with “Protocol (the type) does not to conform to Protocol (the constraint)” error.

Swift Forum: Lifting the “Self or associated type” constraint on existentials

Eventually SE-0309, challenges of generalized existentials and much more. Heavy-weight discussions about both technical challenges, Swift language’s UI and smoother learning path. Also see the linked posts.

Swift Forum: [Discussion] Easing the learning curve for introducing generic parameters

Developers reach for existential types instead of generics, because they don’t have a deep enough understanding of both. It’s more natural to use existential types, as value-level abstraction, but it has limits. At some point, type-level abstraction (i.e. generics) is the right choice.

Providing another rationale to existential any: designing progressive disclosure.

Swift Doc: Dynamic Casting Behavior

What happens when you cast with the as? operator, etc. There are all kinds of specific rules including those that involve existentials.

Apple

The Swift Programming Language: Types

Swift official docs. Definition of types includes protocols. Names & compound types. Opaque type, metatype type, Self type.

The Swift Programming Language: Protocols

Note Protocol as Types, “Because protocols are types…” etc. Note Collections of Protocol Types.

The Swift Programming Language: Opaque Types

Technical explanation and examples of opaque types. Comparison between opaque types and protocol types. Mentioning problems and limitations of using protocol types as function return types, like problem with Self requirements, and the value of a protocol type not conforming to the protocol.

WWDC 2016: Understanding Swift Performance

Low-level details of existential containers, protocols, genercis (among many, many other things)

Dynamic Casting Behavior

TBD

Cacoaphony (Rob Napier)

Cacoaphony

Type erasure implementations etc., TBD

SwiftRocks (Bruno Rocha)

Understanding Opaque Return Types in Swift

Explains the opaque return type, in a way that focuses on the role of the opaque type “hiding” the actual return type, and that it makes our lives easier.

Pofat’s blog

any Protocol Is Now Existential

Discusses SE-0309 and SE-0335, existential container for PATs, existential any, metatypes

重新檢視 Swift 的 Protocol(二)

Existential container memory layout, witness table, limits of PAT. There is no part 1.

Opaque Result Type

Opaque result type: what, why, and limitations.

重新檢視 Swift 的 Protocol(三)

Implementing protocol witness table yourself (as a generic struct) (ref. Brandon Willams’s talk)

Tim Ekl

Swift Generics Evolution

Swift Generics 2: Existentials Boogaloo

Others

詳解 Swift 各種 Type Polymorphism 找出最適合的實作方式!

StackOverflow: Protocol doesn’t conform to itself?

Swift by Sundell: Why can’t certain protocols, like Equatable and Hashable, be referenced directly?

Simple examples of trouble with existentials when Self or associate type is involved.

Existential types in Rust

Leave a Reply

Your email address will not be published.