Open5
try! Swift Tokyo Meetup参加記
Swift Expression Macros: a practical introduction -実践Swiftマクロ入門-
メモ
- プロポーザルでまだ正式リリースされていない機能
- A Possible Vision for macros in Swift
- SE-0382
- マージはされていて試すこともできる
- 今まであった似た機能→
#function
、#colorLiteral
など - 提案された例
-
#printArguments()
→print(#function)
的な挙動
-
- 外部から見れば文字列の置き換えをやっているだけ
- 内部的にはSwift Syntaxでやっている
- 文字列でやるとパターンが爆発するためsyntax treeの状態で処理している
- ただし、Swift Syntax自体が抽象度が低いのでtrivia(不要な空白など)を処理しなければいけないのは結局残っていてそこが議論ポイント
- ポイント
- タイプセーフ
- 構文を変換している
- ビルドタイムに実行とチェックを行う
- サンドボックス内で実行される→ネットワーク・ファイルなどは繋げられない → 将来的にファイルに関しては指定して許可する挙動も検討されている
- コンパイル時のチェック→URLなどのチェックをコンパイル時にするマクロを作ることもできる→アンラップなどをする必要がなくなる
- ドメイン制限なども作ることができる
- 関数やResult Builder, Property Wrapperでできることはマクロにしないほうがデバッグなどしやすい
- コード生成のツールとして見るのがいい
- async関数につけるとcompletionHandlerを使ったコードも自動で生成するマクロとか
- アスペクト指向というプログラミングパラダイムを実現するとか
- powerassertとか
実装方法例
@expression public macro
colorLiteral(
red: Float, green: Float, blue: Float, alpha: Float
) -> _ColorLiteralType
= #externalMacro(module: "MacroExamplesPlugin", type: "ColorLiteralMacro")
// 別モジュールにある想定↓
public struct ColorLiteralmacro: ExpressionMacro {
public static func expansion(
of macro: MacroExpansionExprSyntax,
in context: inout MacroExpansionContext
) -> ExprSyntax {
// ...
}
}
リンク
Optimizing your Swift code
メモ
- V8 ... LiftoffがBaseline、TurboFanでOptimizing
- benchmarks game
- 遅いのは...
- 高レベルな言語機能を使っているため遅くなる(ex. ARC, CoW, Protocol)
- 短いコードでもふんだんに命令が吐かれる
- コンパイラフレンドリー=コンパイラが最適化しやすいコードの書き方
- Profile(Instruments.app)を見る → GPU、Event latency、Blocking IOなどがボトルネックになりがち
- ユニットテストなどでとるのがいい、テストのところから個別にProfileできる
- dynamic dispatchをなるべく減らす
- クラスは無闇にopenをつけない→overrideされていないことがわかっていれば呼び出し先が一つに定まることができるため
- プロトコルはexistentialを避ける、
some
をつけるなど - module分割しているとdynamic dispatchが効かない書き方をしがち
- structはtrivialな型な時だけ軽量=Plain Old Data: No extra copy, move, destruction semantics
- trivialかどうかは
_isPOD()
で判断できる
Beelineライブラリの紹介: iOS でのルーティングに対する新たなアプローチ
Swift Concurrency in GoodNotes
- SwiftWASMとRxは相性が悪い
- → RxをConcurrencyに
- Migration→ブリッジAPIを作る→RxにあってConcurrencyにないAPIを作る→徐々に置き換える
- Single<A> と () async throws -> Aの変換
- Observable<A> と AsyncThrowingStream<A, Error>の変換
- ないAPI
- Rxオペレータ
- Disposebag
- Testableなスケジューラ
- BehaviorRelay, @Published
- Rxオペレータ:apple/swift-async-algorithms, sideeffect-io/AsyncExtensions, reddavis/Asynchrone
- UIKitとAsyncStreamを同期するのは難しい
- Disposebag:CancelBagというクラスを作る(Sendableで中でtaskを貯めてdeinitでキャンセルするもの)
- テストスケジューラ:await Task.yield()を使えば解決できるが、二個以上書いても動いてしまう→pointfreeco/swift-clocksのmegaYieldがmore reliableだが完全には置き換えられたとは言えない
- Reliably testing code that adopts Swift Concurrency?
- CombineはSwiftWASMでは使えない→@Publishedが使えない
- → for awaitを使う、ただしSharedAsyncSequenceを使わないと別々でやった時に同じ値を取れない
- → SharedcurrentValueSequenceを作って使う
- OpenCombine/ObservableObject.swift