🚫

~Copyable(NonCopyable)のdiscard selfについて

2024/02/08に公開

Swift 5.9で追加された~Copyableのdiscard selfを試して見ると変なエラーが出たので調べてみた。

問題

まずStringプロパティを一つ持つstructに~Copyableを付ける。

struct Dummy: ~Copyable {
    var value = ""
}

次にconsumingメソッドにdiscard selfを追加する。

struct Dummy: ~Copyable {
    var value = ""
    
+    consuming func consume() {
+        discard self
+    }
}

すると以下のエラーが表示される。

deinitがないとダメそうなのでdeinitを追加してみる。

struct Dummy: ~Copyable {
    var value = ""
    
    consuming func consume() {
        discard self
    }
    
+    deinit {}
}

すると今度は以下のエラーが表示される。

原因

色々調べてみるとtrivially-destroyed stored propertiesとはInt, Boolのように使用後に追加のメモリ解放が必要ないタイプのことで、全プロパティがtrivially-destroyed stored propertiesである場合のみdiscardは使えるようだ。

すなわちString、Arrayなどをプロパティで持つ場合、discard selfは使えない。

Trivial Types
Trivial types can be copied by copying the bits of a value of the trivial type and do not need any special destruction logic. Trivial types are inferred by the compiler and cannot be specified using an attribute. Trivial types own their storage, so rules below that apply to owned types also apply to trivial types (specifically regarding projections). Pointers are not trivial types. When Objective-C++ mode is enabled, C++ types that hold Objective-C classes are still considered trivial, even though they technically violate the above contract.

結果

String、Arrayなどのプロパティを持つか持たないかで、discard selfが使えたり、使えなかったりすることがわかった。

気になる点

本当に~Copyableを使ってるプロジェクトがあるのか気になって調べてみると、Swift Foundationのコードの中にあった。

~CopyableタイプのOutputBufferと
https://github.com/apple/swift-foundation/blob/171e2a75dafc066700886ce87e8cd592ab5edef8/Sources/FoundationEssentials/OutputBuffer.swift#L13

そのOutputBufferを使ってDateComponentsをISO8601Formatの文字列に変換するところ
https://github.com/apple/swift-foundation/blob/main/Sources/FoundationEssentials/Formatting/Date%2BISO8601FormatStyle.swift#L303

めでたしめでたし、

参照

SE-0390 Noncopyable structs and enums

http://www.csl.cool/2023/06/05/ios-dev/swift/swift-noncopyable-types-and-variable-ownership/

https://zenn.dev/ojun_9/articles/d2c49dcd721c17

https://www.hackingwithswift.com/swift/5.9/noncopyable-structs-and-enums

Discussion