Open4

[Swift] actorにおけるfinal修飾子とは?

ukitakaukitaka

Swift 5.10 / Xcode 15.4

MainActor の定義をみると actorに対して final がついている

@globalActor final public actor MainActor : GlobalActor { ... }

自作のactorに対しても final にすることが可能

final actor MyActor { } // OK

しかし、actor は (finalかどうかに関わらず) 継承はできない

ukitakaukitaka

actorのproposalの時点では継承を許可するかどうかの議論はあったが、結果的に有用性よりコストが大きく採用しないことに決めた、とのこと。

Actor inheritance
...
Subsequent review discussion determined that the conceptual cost of actor inheritance outweighed its usefulness, so it has been removed from this proposal.

https://github.com/swiftlang/swift-evolution/blob/2c10ffea15f5fdc41b32f0e78fe17b0b975adc8e/proposals/0306-actors.md#alternatives-considered

ukitakaukitaka

継承できない(= オーバーライドできない) のにfinalがつけられることに対して、ForumにJoeGroff氏からの投稿(May 2023時点) を見つけた

As an API contract, being final is an assertion that there will never be subclasses of a type, not just that there don't happen to be any right now. For actors we decided not to implement inheritance, but left the door open to it possibly happening later.

現時点では継承はできないが、今後できるようにする可能性もあるので 文法上は final は許可しているということらしい。

https://forums.swift.org/t/why-can-you-constrain-to-final-classes-and-actors/65256/4

ukitakaukitaka

ただ、Language Referenceの文法定義 上は actorに対して final はつけられないことになっているので、背景を知らないと少し混乱を招きそう。

actor-declaration → attributes? access-level-modifier? actor actor-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? actor-body
actor-name → identifier
actor-body → { actor-members? }

actor-members → actor-member actor-members?
actor-member → declaration | compiler-control-statement

( finalattributes でも access-level-modifier でもない )
参考: classの場合は final がある

class-declaration → attributes? access-level-modifier? final? class class-name generic-parameter-clause? type-inheritance-clause? generic-where-clause? class-body

https://docs.swift.org/swift-book/documentation/the-swift-programming-language/declarations#Actor-Declaration