33
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

classにfinalを付ける基準(Swift)

Last updated at Posted at 2021-12-20

はじめに

本記事は Swift/Kotlin愛好会 Advent Calendar 2021 の20日目の記事です。

Swiftで classfinal キーワードを付ける基準を考察します。

環境

  • OS:macOS Big Sur 11.6
  • Swift:5.5.2
  • Xcode:13.2 (13C90)

「finalキーワード」とは?

classfinal キーワードを付けると、そのクラスを継承できなくなります。

以下のように 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の公式ブログで「 finalprivate を付けて動的ディスパッチを減らすことで、パフォーマンスが向上する」と明記されています。

本記事で詳細は説明しませんが、とにかくパフォーマンスを優先するプロジェクトでは、継承されていない全クラスに final を付けるのがいいと思います。

Twitterを見る限りでは、2022/02/25現在でも final を付けてパフォーマンスが向上するケースは多そうです。
特に競プロでSwiftを使うときは final を付けるべきだと思いました。

finalを使っていなく、プロジェクトでfinalに関する方針もない

そもそもプロジェクトで final キーワードを使っていなく、プロジェクトで特に方針がないパターンです。
まず方針を決めるべきだとは思いますが、特に決めない場合は、パフォーマンスの観点からも継承されていない全クラスに final を付けるのがいいと思います。

継承できるかどうかを考えてクラスを設計していて、それをわかるようにしたい

final は継承されているかどうかの目印ではない、継承できない設計になっているクラスにのみ final を付けるべきだ」
「クラスを使う側によってクラスの実装が決まるのはおかしい、属性は他に依存せずに決めるべきだ」
このような意見をTwitterなどで確認しました。

どちらも私にはない考えだったので、目から鱗が落ちました。
確かに継承されていない全クラスに final を付けると、継承できる設計になっているかどうかはわかりません。

簡潔にまとめると以下となります。

  • final が付いている → 継承できるように設計されていない
  • final が付いていない → 継承できるように設計されている

おまけ: デフォルトで継承できないようにすべき?

Kotlinはデフォルトでクラスが継承できず、 open キーワードを付けることで継承できるようになります。

Swiftもデフォルトで継承できないように議論がされていますが、実現には至っていません。

おわりに

どちらの方針を採用するかはプロジェクトごとに決めるのがいいと思います。
私の好みは変わらず「継承されていない全クラスに final キーワードを付ける」ですが、他の考えを知れて勉強になりました。

Swift以外の言語でもいいので、 final キーワードの使いどころに関する公式ドキュメントや、他の意見がありましたら、教えていただけると嬉しいです :relaxed:

以上 Swift/Kotlin愛好会 Advent Calendar 2021 の20日目の記事でした。
明日は @katopan さんです。

参考リンク

33
14
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
33
14

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?