Attachments

[Previous << Inbox](https://qiita.com/flowcadence/items/db88a071c732f68cc7fb)
[Next >> Contracts](https://qiita.com/flowcadence/items/91a5ecb5812af1f98bef)

https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a#cadenceの言語仕様を学ぶ

Attachmentsは、開発者が構造体やリソースタイプ（宣言されていないものも含む）を、そのタイプのオリジナルの作成者が意図した動作を計画したり考慮したりすることなく、新しい機能で拡張できるように設計されたCadenceの機能です。

<h1 id="Declaring-Attachments">Declaring Attachments</h1>

Attachmentsは、`attachment`キーワードで宣言され、これは新しい形式の複合宣言を使用して宣言されます。`attachment <Name> for <Type>: <Conformances> { ... }`ここで、Attachmentsの関数とフィールドは本体で宣言されます。したがって、以下はAttachmentsの合法(有効)な宣言の例となります。

```ruby
access(all)
attachment Foo for MyStruct {
    // ...
}

attachment Bar for MyResource: MyResourceInterface {
    // ...
}

attachment Baz for MyInterface: MyOtherInterface {
    // ...
}
```
他のすべての型宣言と同様に、Attachmentsは`all`のアクセス権限で宣言される必要があります。

Attachmentsの種類（構造体またはリソース）を指定する必要はありません。その種類は、拡張する型と同じ種類になるからです。ベース型(base type)は、具体的な複合型(composite type)またはインターフェースのいずれかであることに注意してください。前者の場合、Attachmentsは、そのベース型に明確に属する値でのみ使用可能であり、インターフェースの場合、Attachmentsは、そのインターフェースに準拠する任意のタイプで使用可能です。

Attachmentsの本体は、複合型と同じ宣言規則に従います。特に、フィールド・メンバーと関数メンバーの両方を持つことができ、フィールド・メンバーはすべて初期化子(init)で初期化する必要があります。リソース・メンバーを持つことができるのは、リソース・タイプであるAttachmentsのみです。
`self`キーワードはアタッチメント本体で使用できますが、複合型とは異なり、`self`は複合型ではなく**参照型**です。`A`に対するアタッチメント宣言では、`self`の型は`A`への参照となり、他の複合型宣言のように`A`ではなくなります。この参照が持つ特定の権限は、`self`参照が現れるメンバ関数に関連付けられたアクセス修飾子に依存し、以下で詳しく説明します。

Attachmentのリソースが`destroy`された場合、そのAttachmentはすべて不特定の順序で`destroy`されます。この場合のAttachmentの破棄順序について唯一保証されているのは、ベースリソース(base resource)が最後に破棄されるということです。

Attachmentの本文内には`base`キーワードも利用可能であり、Attachmentのベース値への参照が含まれています。つまり、Attachmentが添付されている複合型です。したがって、その型はAttachmentの宣言されたベース型への参照となります。つまり、`access(all) attachment Foo for Bar`と宣言されたAttachmentの場合、`Foo`の`base`フィールドの型は`&Bar`となります。したがって、例えば、以下のようなAttachmentの宣言は有効です。
```ruby
access(all)
resource R {

    access(all)
    let x: Int

    init (_ x: Int) {
        self.x = x
    }

    access(all)
    fun foo() { ... }
}

access(all)
attachment A for R {
    
    access(all)
    let derivedX: Int

    init (_ scalar: Int) {
        self.derivedX = base.x * scalar
    }

    access(all)
    fun foo() {
        base.foo()
    }
}
```
外部による変異チェックや[access control](https://qiita.com/flowcadence/items/572df270135946f5290e)の目的では、Attachmentはベースタイプとは別の宣言とみなされます。したがって、開発者は`base`値の`access(self)`フィールド（またはAttachmentが別のスマートコントラクトで定義されている場合は`access(contract)`フィールド）にアクセスすることはできません。また、配列やディクショナリ型のフィールドを変更することもできません。
```ruby
access(all)
resource interface SomeInterface {

    access(all)
    let b: Bool

    access(self)
    let i: Int

    access(all)
    let a: [String]
}
access(all)
attachment SomeAttachment for SomeContract.SomeStruct {

    access(all)
    let i: Int

    init(i: Int) {
        if base.b {
            self.i = base.i // cannot access `i` on the `base` value
        } else {
            self.i = i
        }
    }

    access(all)
    fun foo() {
        base.a.append("hello") // cannot mutate `a` outside of the composite where it was defined
    }
}
```

Attachmentのメンバ関数内では、`base`および`self`参照は、関数のアクセス修飾子が指定するものと同じ権限を有します。例えば、`access(all) attachment A for R`として宣言されたAttachmentにおいて、関数`access(E) fun foo()`の定義内では、`base`の型は`auth(E) &R`となり、`self`の型は`auth(E) &A`となります。したがって、以下の定義は有効です。
```ruby
resource R {
    access(E)
    fun foo() {
        //...
    }
}

access(all)
attachment A for R {
    access(E)
    fun bar() {
        base.foo() // available because `E` is required above, and thus `base` is type `auth(E) &R`.
    }
}
```

しかし、これは動作しません（無効です）。
```ruby
resource R {
    access(E)
    fun foo() {
        //...
    }
}

access(all)
attachment A for R {

    access(self)
    fun bar() {
        base.foo() // unavailable because this function has `self` access, and thus `base` only is type `&R`.
    }

}
```
ここで、`self`および`base`値に権限(entitlements)が伝播される方法の結果として、Attachment定義はベース値(base values)がサポートする権限のみをサポートできることに注意してください。すなわち、`R`用に定義されたAttachment `A`は、その定義で権限*E*を使用できるのは、`R`がその定義（または準拠するインターフェースの定義）で`E`も使用している場合のみです。

<h1 id="Attachment-Types">Attachment Types</h1>

`access(all)` 宣言されたAttachment `A for C { ... }` の名目上の型は `A` となります。

アタッチメントは第一級の値(原文: first. class values)ではないため、その使用法は一定の制限を受けることに注意することが重要です。そのため、その使用方法には一定の制限があります。特に、それらの型は参照型の外側には現れません。例えば、Attachmentの宣言`attachment A for X {}`が与えられた場合、型`A`, `A?`, `[A]`, `fun(): A`は有効なtype annotationではありませんが、`&A`, `&A?`, [`&A]`と`fun(): &A`は有効です。

<h1 id="Creating-Attachments">Creating Attachments</h1>

Attachmentは、`attach`式を使用して作成され、この式では、Attachmentの初期化とベース値へのアタッチメントが単一の操作で実行されます。Attachmentは第一級の値ではなく、ベース値から独立して存在することはできず、単独で移動させることもできません。つまり、Attachmentコンストラクタを呼び出せるのは、`attach`式の中だけです。Attachment値の作成とAttachmentを密接に結合することで、ユーザーにとってアタッチメントの処理がよりシンプルになります。また、この理由により、リソース添え字は、`attach`式に現れる場合、明示的な`<-`移動演算子を必要としません。

attach式は、`attach`キーワード、添え字値のコンストラクタ呼び出し、`to`キーワード、および添え字の基本値を評価する式で構成されます。添え字の初期化子(init)に必要な引数はすべて、コンストラクタ呼び出しで指定されます。

```ruby
access(all)
resource R {}

access(all)
attachment A for R {
    init(x: Int) {
        //...
    }
}

// ...
let r <- create R()
let r2 <- attach A(x: 3) to <-r
```
`to`キーワードの右辺の式は、アタッチメントのベースのサブタイプである複合値として評価されなければならず、`to`の左辺のコンストラクタが呼び出される前に評価されます。つまり、`base`値はアタッチメントの初期化子(init)の中で利用可能ですが、作成中のアタッチメントはコンストラクタの実行が終了するまでは`base`上でアクセスできないことに注意することが重要です（以下の"Accessing Attachments"のセクションを参照）。
```ruby
access(all)
resource interface I {}

access(all)
resource R: I {}

access(all)
attachment A for I {}

// ...
let r <- create R()
/* has type @R */
let r2 <- attach A() to <-r
/* ok, because `R` is a subtype of `I`, still has type @R */
```
アタッチメントはtype別にbaseに保存されるため、値に同時に存在できるアタッチメントは、各typeにつき1つだけです。 値にすでにアタッチメントが存在する際に、ユーザーがその値にさらにアタッチメントを追加しようとすると、Cadenceは実行時エラーを発生させます。 `attach` 式によって返される型は、`to` の右辺の式と同じ型です。アタッチメントを値にattach(アタッチ)しても、その型の変更は行われません。

<h1 id="Accessing-Attachments">Accessing Attachments</h1>

Attachmentは、type-indexを介して複合型でアクセスされます。複合型の値は、キーがtypeで値がAttachmentであるディクショナリのような機能を持ちます。複合型値`v`が与えられた場合、インデックス構文を使用して、`v`上の`A`という名前のAttachmentを検索することができます。

```ruby
let a = v[A] // has type `&A?`
```

この構文では、`A` が名詞アタッチメント型であり、`v`が`A`の宣言された基本型のサブタイプである複合型を持つことが必要です。前述の通り、アタッチメントは第一級の値ではないため、このインデックス処理では、`v`上のアタッチメントへの参照が返され、アタッチメント自体は返されません。指定された型のアタッチメントが `v`上に存在しない場合、この式は `nil`を返します。

アタッチメントへのアクセスが許可される権限のセットは、ベース値が許可される権限のセットと同じです。例えば、`A`の定義が以下のようになっている場合：

```ruby
entitlement E 
entitlement F 

resource R {
    access(E)
    fun foo() {
        // ... 
    }

    access(F)
    fun bar() { 
        // ... 
    }
}

attachment A for R {
    access(E | F)
    fun qux() { 
        // ... 
    }
}

// ... 

let a = v[A]!
```

`v`が型`&R`を持つ場合、`a`の結果の型は未承認の `&A`となります。逆に、`v`が型 `auth(E) &R`を持つ場合、`a`の型は同じものに承認されます。すなわち、`auth(E) &A`となります 最後に、`v`が参照（すなわち、`R`型の所有値）でない場合、`a`は`A`に対して「完全な権利」を持つことになります。`A`によって言及されるすべての権利が与えられます。すなわち、この場合、`a`の型は`auth(E, F) &A`となります。

これは、`Identity`[権限マッピング](https://qiita.com/flowcadence/items/572df270135946f5290e#entitlement-mappings)の動作とほぼ同等です。実際、アタッチメントは、ベース値上の`Identity`マッピング・フィールドであると考えることができます。

<h1 id="Removing-Attachments">Removing Attachments</h1>

アタッチメントは、`remove` ステートメントを使用して値から削除することができます。このステートメントは、`remove` キーワード、削除するアタッチメントの名詞(原文: nominal)型、`from`キーワード、およびアタッチメントを削除する対象となる値で構成されます。

from の右辺の値は、アタッチメントの型の宣言されたベースのサブタイプである複合値でなければなりません。

例えば、アタッチメントをサポートするタイプを持つリソース `r` からアタッチメント `A` を削除するには、以下のようになります。
```ruby
remove A from r
```
ステートメントが実行された後、`from` の右辺にある複合値にはAttachmentは含まれなくなります。 値に `remove` キーワードの後に表示されるAttachmentが含まれない場合、このステートメントは効果を持ちません。

Attachmentは、どのタイプからでも任意の順序で削除することができます。そのため、ユーザーは、他のAttachmentの特定の動作に依存するようなアタッチメントを設計しないよう注意する必要があります。

Attachmentを含むリソースが`destroy`された場合、そのアタッチメントはすべて任意の順序で`destroy`されます。

翻訳元

https://cadence-lang.org/docs/language/attachments

***
<b>[Previous << Inbox](https://qiita.com/flowcadence/items/db88a071c732f68cc7fb)
</b>

[Flow blockchain / Cadence version1.0ドキュメント](https://qiita.com/flowcadence/items/3073d69c6e9895e68b5a) (Attachments)

<b>[Next >> Contracts](https://qiita.com/flowcadence/items/91a5ecb5812af1f98bef)</b>