はじめに
本記事は Swift/Kotlin愛好会 Advent Calendar 2021 の20日目の記事です。
Swiftで class
に final
キーワードを付ける基準を考察します。
環境
- OS:macOS Big Sur 11.6
- Swift:5.5.2
- Xcode:13.2 (13C90)
「finalキーワード」とは?
class
に final
キーワードを付けると、そのクラスを継承できなくなります。
以下のように final
キーワードが付いたクラスを継承しようとすると、 inheritance from a final class 'Foo'
のようにビルドエラーが発生します。
final class Foo {}
class Bar: Foo // !!!: ビルドエラー
詳細は以下の記事がわかりやすいです。
結論
先に結論を述べます。
大きく2パターンの結論があると考えました。
結論1
- 継承されていないクラスに目印を付けたい
- とにかくパフォーマンスを優先したい
-
final
を使っていなく、プロジェクトでfinal
に関する方針もない
→ 継承されていない全クラスに final
を付ける
結論2
- 継承できるかどうかを考えてクラスを設計していて、それをわかるようにしたい
→ 継承できる設計になっていないクラスにのみ final
を付ける
追記
そもそもSwiftでクラスの継承はアンチパターンで、UIKitの都合などどうしても必要な場合のみ継承すべきなので、無条件で継承されていない全クラスに final
を付けるのがベターだと思います。
考察
結論だけ見てもわかりづらいので、詳細に考察していきます。
継承されていないクラスに目印を付けたい
今まで私はこの考えしかありませんでした。
Twitterなどで他にも様々な考えがあると知ったのが、本記事を執筆した理由です。
継承されていない全クラスに final
を付けることで、クラスを見ただけで継承されているかどうかがわかり、可読性が高くなると考えています。
こうすることで「クラスに final
が付いていない → このクラスは継承されているんだな」とわかるようになります。
簡潔にまとめると以下となります。
-
final
が付いている → 継承されていない -
final
が付いていない → 継承されている
もし継承したくなったら final
を外せばいいだけです。
ただSwiftで継承したいことはあまりないはずです。
とにかくパフォーマンスを優先したい
6年半前の記事なので今と違うかもしれませんが、Appleの公式ブログで「 final
や private
を付けて動的ディスパッチを減らすことで、パフォーマンスが向上する」と明記されています。
本記事で詳細は説明しませんが、とにかくパフォーマンスを優先するプロジェクトでは、継承されていない全クラスに final
を付けるのがいいと思います。
Twitterを見る限りでは、2022/02/25現在でも final
を付けてパフォーマンスが向上するケースは多そうです。
特に競プロでSwiftを使うときは final
を付けるべきだと思いました。
finalを使っていなく、プロジェクトでfinalに関する方針もない
そもそもプロジェクトで final
キーワードを使っていなく、プロジェクトで特に方針がないパターンです。
まず方針を決めるべきだとは思いますが、特に決めない場合は、パフォーマンスの観点からも継承されていない全クラスに final
を付けるのがいいと思います。
継承できるかどうかを考えてクラスを設計していて、それをわかるようにしたい
「 final
は継承されているかどうかの目印ではない、継承できない設計になっているクラスにのみ final
を付けるべきだ」
「クラスを使う側によってクラスの実装が決まるのはおかしい、属性は他に依存せずに決めるべきだ」
このような意見をTwitterなどで確認しました。
どちらも私にはない考えだったので、目から鱗が落ちました。
確かに継承されていない全クラスに final
を付けると、継承できる設計になっているかどうかはわかりません。
簡潔にまとめると以下となります。
-
final
が付いている → 継承できるように設計されていない -
final
が付いていない → 継承できるように設計されている
おまけ: デフォルトで継承できないようにすべき?
Kotlinはデフォルトでクラスが継承できず、 open
キーワードを付けることで継承できるようになります。
Swiftもデフォルトで継承できないように議論がされていますが、実現には至っていません。
おわりに
どちらの方針を採用するかはプロジェクトごとに決めるのがいいと思います。
私の好みは変わらず「継承されていない全クラスに final
キーワードを付ける」ですが、他の考えを知れて勉強になりました。
Swift以外の言語でもいいので、 final
キーワードの使いどころに関する公式ドキュメントや、他の意見がありましたら、教えていただけると嬉しいです
以上 Swift/Kotlin愛好会 Advent Calendar 2021 の20日目の記事でした。
明日は @katopan さんです。