Pofat 的話
發刊日的同時 WWDC22 也正式開始,有興趣的朋友們歡迎一起到 weak self 的 Discord 參加 WWDC22 Keynote Watch Party ,新朋友記得先到「🆕報到區」打招呼喔!此外我和 13 會一起參加 6/11 晚上 8-9 點的 WWDC.playground 直播節目,這是由 SwiftGG 翻译组、T技术沙龙、老司机周报等單位一起主辦的活動,在此先祝大家能盡情地享受一年一度的蘋果嘉年華!
Swift 新代誌
👀 SE-0359 Build-Time Constant Values (Reviewing)
這個 SE 引起了不少的正反面討論,目前的提案是引入一個新的 attribute @const
( 又多一個,Swift 應該已在語言界榮登 keyword 數量冠軍)
struct DatabaseParams {
@const let encoding: String = "utf-8" ✅
@const let capacity: Int = Int.random(in: 1..<10) ❌
}
func acceptConst(@const _ string: String) { ... }
acceptConst("test") ✅
立意是減少大家 static 的用量以及在開發者使用 magic number 時做保護,確定它是個常數而不是魔法再魔法 🪄,不過也有開發者抱持不同看法,就反方觀點簡單摘要如下:
Runtime 的 assert 和 precondition 仍然是非常必要的,magic number 就算放到 compile time 就確定還是個 magic ,對事情未必有益。
這個提案本身功能略薄弱,若和更完整的 build-time evalution 一同提出可能會更理想。
👀 SE-0360 Opaque result types with limited availability (Reviewing)
顯然是為了 SwiftUI 推出更多新元件時的支援語法,比如你有一個新版本 OS 才能使用的元件:
@available(macOS 100, *)
struct SuperRectangle : Shape {
...
}
這 SE 讓你可以加上 if #available
來控制不同 OS 行為:
func test() -> some Shape {
if #available(macOS 100, *) { ✅
return SuperRectangle()
}
return self
}
早該有了嘛不然我們怎麼用新元件!舊的都有 bug 啊!
🛠️Differentiable Swift 現況
Differentiable Swift 是 Swift for TensorFlow (S4TF) 計畫中為微分相關運算而生的功能集合,值得一提的是,@differentiable
和 Differentiable protocol
帶有編譯器黑魔法,能夠在編譯過程中生成 SIL 的階段計算微分結果並插入,這裡的計算其實是把數學函式拆成預先定義好的基礎函式之組合(加法、乘法等),再把每個的微分結果組合起來,有興趣深究原始碼的人可以看 John Lin 在 2019 iPlayground 的探索 Swift 自動微分實作。
一位團隊前成員整理了過去一年進行的主要工作以及目前尚待解決的 issue,有興趣在此領域的人是個入坑的好時機!雖然這不是我熟悉的領域,很高興看到這有趣的計畫能夠繼續運作下去(當初名字能叫 Swift for TensorFlow 而不是反過來就很霸氣了) ,期待未來在科學運算領域的發展或是大一微積分從此變成程式課。
也許你會想說既然有 Differentiable Programming ,那怎麼沒有 Integral Programming?以下就是原因。。。
📦 To Erase Or Not To Erase ?
在 Swift 裡,有 associated type 的 protocol 無法生成 existential container ,比如考慮一個 Request protocol ,裡面需定義一個方法將透過 network response 收到的 data 轉為某個資料型別 `Result` ,直接用它生成 existential container 原先是禁止的:
protocol Request<Result> {
associatedtype Result
func parse(data: Data) -> Result?
}
let request: Request ❌
常見的處理方式是以另一個泛型型別替代,從使用者的角度看來抺去了 associated type,是故稱之 type erasure:
struct AnyLegacyRequest<T>: Request {
private let handler: (Data) -> T?
init(handler: @escaping (Data) -> T?) {
self.handler = handler
}
func parse(data: Data) -> T? {
return handler(data)
}
}
let request = AnyLegacyRequest(handler: { ...})
然而上一期波報有提到 existential 與泛型趨於完整,經由這些新功能我們可以更簡潔地達到同樣目的:
(p.s. 發刊時下面的程式碼仍然無法成功編譯,待完善)
struct AnyRequest<T>: Request {
var wrapped: any Request<T>
func parse(data: Data) -> T? {
return wrapped.parse(data)
}
}
休蛋幾咧,能有更簡潔的寫法是很高興,只是既然我們啥 protocol 都可以做 existential container 了,那真的還需要把型別抺掉嗎?
let request: any Request ✅
😵💫 Protocol 的 Existential Container 並不遵循該 Protocol
這個概念可能是 Swift 5.7 的 any
新語法上路後最容易撞牆的部分,舉例來說你很可能興奮地寫出下列程式碼卻發現不可行:
let one: any Equatable = 1
let stillOne: any Equatable = 1
print(one == stillOne) ❌
Existential container 只是個容器,你可以直接對容器取得 protocol 裡定義的元件與函數,但容器本身並不遵循該 protocol (not conform to the protocol),所以在上例中的 any Equatable
無法套用 == 。
🉑 我想通通摻在一個 Array 裡做撒尿牛丸啊
大家對 existential container 最詬病的就是在有 Self 或 associated type 時無法把不同型別的元素都塞入一個 Array 裡 (Heterogenous Array) 啊用NSArray不就好了,當你想要一次管理多個 Request 時卻發現這樣無法把它們都塞進 Array 裡:
let requests: [Request] ❌
現在有了 any
加持,你可以塞進五花八門的 Request,塞好塞滿(雖然我個人會選擇下面後者的寫法):
let mixRequest:[any Request] = [IntRequest(), StringRequest()] ✅
let intRequests:[any Request<Int>] = [IntRspRequest()] ✅✅
只是在需要用 protocol 來表示「身份」時你就無法依靠 any 了,比如要求 key 必須是 Hashable
的 Dictionary 就不能像下面這樣宣告 ,因為 any Hashable
並不遵循 Hashable:
let dict: [any Hashable: String] = [1: "test"] ❌
在這個情況下就會需要 AnyHashable
這樣的容器,最終極的官方解法可能是允許下列語法,只是恐有些安全性的考量,目前尚未有譜。
extension any Hashable: Hashable { ... }
最後,根據核心團隊聲稱,這種 type erasure 的寫法能夠向前相容,少傷了開發者很多腦筋,只是無法在 runtime 取得它的成員資訊 (Metadata),但相信大多時候你不需要這種功能的。
Pofat 精選
13 的全新 SwiftUI 專欄上線,這絕對是前所未見的教學專欄,專治焦慮,讀了就知道!
Protocol with Self or associated type requirements is the new sexy.
看到笑死的新推特帳號,雖然遲到但絕不會缺席的 Swift 小知識(大概五年那麼遲跟本報一樣)。
寫完本期的同時 Paul Liu 關於 type erasure 的新文章(part 2)也很巧地同時上線,鉅細靡遺地呈現來龍去脈與思考過程,非常精彩,推薦給大家坐下來細嚼慢嚥:
Swift Protocols and Generics, Part 1: Protocol 和其他 Type 有什麼不一樣?
Swift Protocols and Generics, Part 2: Protocol as Type 和 Type Erasure 有什麼關係?