You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Copy file name to clipboardExpand all lines: docs/language/attachments.mdx
+44-95Lines changed: 44 additions & 95 deletions
Display the source diff
Display the rich diff
Original file line number
Diff line number
Diff line change
@@ -3,15 +3,13 @@ title: Attachments
3
3
sidebar_position: 17
4
4
---
5
5
6
-
Attachments are a feature of Cadence designed to allow developers to extend a struct or resource type
7
-
(even one that they did not declare) with new functionality,
8
-
without requiring the original author of the type to plan or account for the intended behavior.
6
+
Attachments are a feature of Cadence designed to allow developers to extend a struct or resource type (even one that they did not create) with new functionality, without requiring the original author of the type to plan or account for the intended behavior.
9
7
10
-
## Declaring Attachments
8
+
## Declaring attachments
11
9
12
-
Attachments are declared with the `attachment` keyword, which would be declared using a new form of composite declaration:
13
-
`attachment <Name> for <Type>: <Conformances> { ... }`, where the attachment functions and fields are declared in the body.
14
-
As such, the following would be examples of legal declarations of attachments:
10
+
Attachments are declared with the `attachment` keyword, which is declared by using a new form of the composite declaration:`attachment <Name> for <Type>: <Conformances> { ... }`, where the attachment functions and fields are declared in the body.
11
+
12
+
As such, the following are examples of legal declarations of attachments:
15
13
16
14
```cadence
17
15
access(all)
@@ -28,34 +26,19 @@ attachment Baz for MyInterface: MyOtherInterface {
28
26
}
29
27
```
30
28
31
-
Like all other type declarations, attachments may only be declared with `all` access.
29
+
Like all other type declarations, attachments can only be declared with `all` access.
32
30
33
-
Specifying the kind (struct or resource) of an attachment is not necessary, as its kind will necessarily be the same as the type it is extending.
34
-
Note that the base type may be either a concrete composite type or an interface.
35
-
In the former case, the attachment is only usable on values specifically of that base type,
36
-
while in the case of an interface the attachment is usable on any type that conforms to that interface.
31
+
Specifying the kind (struct or resource) of an attachment is not necessary, as its kind will necessarily be the same as the type it is extending. Note that the base type may be either a concrete composite type or an interface. In the former case, the attachment is only usable on values specifically of that base type, while in the case of an interface, the attachment is usable on any type that conforms to that interface.
37
32
38
-
The body of the attachment follows the same declaration rules as composites.
39
-
In particular, they may have both field and function members,
40
-
and any field members must be initialized in an initializer.
41
-
Only resource-kinded attachments may have resource members.
33
+
The body of the attachment follows the same declaration rules as composites. In particular, they may have both field and function members, and any field members must be initialized in an initializer. Only resource-kind attachments may have resource members.
42
34
43
-
The `self` keyword is available in attachment bodies, but unlike in a composite,
44
-
`self` is a **reference** type, rather than a composite type:
45
-
In an attachment declaration for `A`, the type of `self` would be a reference to `A`, rather than `A` like in other composite declarations.
46
-
The specific entitlements that this reference has depends on the access modifier associated with the member function in which the `self` reference
47
-
appears, and is explained in more detail below.
35
+
The `self` keyword is available in attachment bodies, but unlike in a composite, `self` is a **reference** type, rather than a composite type: in an attachment declaration for `A`, the type of `self` would be a reference to `A`, rather than `A` as in other composite declarations. The specific entitlements that this reference has depend on the access modifier associated with the member function in which the `self`-reference appears, and are explained in more detail below.
48
36
49
-
If a resource with attachments on it is `destroy`ed, all its attachments are `destroy`ed in an unspecified order.
50
-
The only guarantee about the order in which attachments are destroyed in this case is that the base resource will be the last thing destroyed.
37
+
If a resource with attachments on it is `destroy`ed, all of its attachments are `destroy`ed in an unspecified order. The only guarantee about the order in which attachments are destroyed in this case is that the base resource will be the last thing destroyed.
51
38
52
-
Within the body of an attachment, there is also a `base` keyword available,
53
-
which contains a reference to the attachment's base value;
54
-
that is, the composite to which the attachment is attached.
55
-
Its type, therefore, is a reference to the attachment's declared base type.
56
-
So, for an attachment declared `access(all) attachment Foo for Bar`, the `base` field of `Foo` would have type `&Bar`.
39
+
Within the body of an attachment, there is also a `base` keyword available, which contains a reference to the attachment's base value; that is, the composite to which the attachment is attached. Its type, therefore, is a reference to the attachment's declared base type. So, for an attachment declared as `access(all) attachment Foo for Bar`, the `base` field of `Foo` would have type `&Bar`.
57
40
58
-
So, for example, this would be a valid declaration of an attachment:
41
+
For example, this is a valid declaration of an attachment:
59
42
60
43
```
61
44
access(all)
@@ -87,14 +70,9 @@ attachment A for R {
87
70
base.foo()
88
71
}
89
72
}
90
-
91
73
```
92
74
93
-
For the purposes of external mutation checks or [access control](./access-control.md),
94
-
the attachment is considered a separate declaration from its base type.
95
-
A developer cannot, therefore, access any `access(self)` fields
96
-
(or `access(contract)` fields if the base was defined in a different contract to the attachment)
97
-
on the `base` value, nor can they mutate any array or dictionary typed fields.
75
+
For the purposes of external mutation checks or [access control], the attachment is considered a separate declaration from its base type. A developer cannot, therefore, access any `access(self)` fields (or `access(contract)` fields if the base was defined in a different contract to the attachment) on the `base` value, nor can they mutate any array or dictionary typed fields.
98
76
99
77
```cadence
100
78
access(all)
@@ -130,9 +108,9 @@ attachment SomeAttachment for SomeContract.SomeStruct {
130
108
}
131
109
```
132
110
133
-
Within an attachment's member function, the `base` and `self` references are entitled to the same entitlements that the function's access modifier specifies.
134
-
E.g., in an attachment declared as `access(all) attachment A for R`, within a definition of a function `access(E) fun foo()`,
135
-
the type of `base` would be `auth(E) &R`, and the type of `self` would be `auth(E) &A`. Thus the following definition would work:
111
+
Within an attachment's member function, the `base` and `self` references are entitled to the same entitlements that the function's access modifier specifies. For example, in an attachment declared as `access(all) attachment A for R`, within a definition of a function `access(E) fun foo()`, the type of `base` would be `auth(E) &R`, and the type of `self` would be `auth(E) &A`.
112
+
113
+
Thus, the following definition works:
136
114
137
115
```cadence
138
116
resource R {
@@ -151,9 +129,10 @@ attachment A for R {
151
129
}
152
130
```
153
131
154
-
while this would not:
132
+
While this does **not** work:
155
133
156
134
```cadence
135
+
// Bad code example. Do not use.
157
136
resource R {
158
137
access(E)
159
138
fun foo() {
@@ -172,32 +151,19 @@ attachment A for R {
172
151
}
173
152
```
174
153
175
-
Note that as a result of how entitlements are propagated to the `self` and `base` values here, attachment definitions can only support
176
-
the same entitlements that their base values support; i.e. some attachment `A` defined for `R` can only use an entitlement `E` in its definition
177
-
if `R` also uses `E` in its definition (or the definition of any interfaces to which it conforms).
154
+
Note that as a result of how entitlements are propagated to the `self` and `base` values here, attachment definitions can only support the same entitlements that their base values support; i.e., some attachment `A` defined for `R` can only use an entitlement `E` in its definition if `R` also uses `E` in its definition (or the definition of any interfaces to which it conforms).
178
155
179
-
### Attachment Types
156
+
### Attachment types
180
157
181
158
An attachment declared with `access(all) attachment A for C { ... }` will have a nominal type `A`.
182
159
183
-
It is important to note that attachments are not first class values, and as such their usage is limited in certain ways.
184
-
In particular, their types cannot appear outside of a reference type.
185
-
So, for example, given an attachment declaration `attachment A for X {}`, the types `A`, `A?`, `[A]` and `fun(): A` are not valid type annotations,
186
-
while `&A`, `&A?`, `[&A]` and `fun(): &A` are valid.
160
+
It is important to note that attachments are not first-class values, and as such, their usage is limited in certain ways. In particular, their types cannot appear outside of a reference type. So, for example, given an attachment declaration `attachment A for X {}`, the types `A`, `A?`, `[A]`, and `fun(): A` are not valid type annotations, while `&A`, `&A?`, `[&A]`, and `fun(): &A` are valid.
187
161
188
-
## Creating Attachments
162
+
## Creating attachments
189
163
190
-
An attachment is created using an `attach` expression,
191
-
where the attachment is both initialized and attached to the base value in a single operation.
192
-
Attachments are not first-class values; they cannot exist independently of a base value,
193
-
nor can they be moved around on their own.
194
-
This means that an `attach` expression is the only place in which an attachment constructor can be called.
195
-
Tightly coupling the creation and attaching of attachment values helps to make reasoning about attachments simpler for the user.
196
-
Also for this reason, resource attachments do not need an explicit `<-` move operator when they appear in an `attach` expression.
164
+
An attachment is created using an `attach` expression, where the attachment is both initialized and attached to the base value in a single operation. Attachments are not first-class values; they cannot exist independently of a base value, nor can they be moved around on their own. This means that an `attach` expression is the only place in which an attachment constructor can be called. Tightly coupling the creation and the attaching of attachment values helps to make reasoning about attachments simpler for the user. Also for this reason, resource attachments do not need an explicit `<-` move operator when they appear in an `attach` expression.
197
165
198
-
An attach expression consists of the `attach` keyword, a constructor call for the attachment value,
199
-
the `to` keyword, and an expression that evaluates to the base value for that attachment.
200
-
Any arguments required by the attachment's initializer are provided in its constructor call.
166
+
An attach expression consists of the `attach` keyword, a constructor call for the attachment value, the `to` keyword, and an expression that evaluates to the base value for that attachment. Any arguments required by the attachment's initializer are provided in its constructor call:
201
167
202
168
```cadence
203
169
access(all)
@@ -215,11 +181,7 @@ let r <- create R()
215
181
let r2 <- attach A(x: 3) to <-r
216
182
```
217
183
218
-
The expression on the right-hand side of the `to` keyword must evaluate to a composite value whose type is a subtype of the attachment's base,
219
-
and is evaluated before the call to the constructor on the left side of `to`.
220
-
This means that the `base` value is available inside of the attachment's initializer,
221
-
but it is important to note that the attachment being created will not be accessible on the `base`
222
-
(see the accessing attachments section below) until after the constructor finishes executing.
184
+
The expression on the right-hand side of the `to` keyword must evaluate to a composite value whose type is a subtype of the attachment's base, and is evaluated before the call to the constructor on the left side of `to`. This means that the `base` value is available inside of the attachment's initializer, but it is important to note that the attachment being created will not be accessible on the `base` (see [accessing attachments] below) until after the constructor finishes executing:
223
185
224
186
225
187
```cadence
@@ -237,29 +199,19 @@ let r <- create R() // has type @R
237
199
let r2 <- attach A() to <-r // ok, because `R` is a subtype of `I`, still has type @R
238
200
```
239
201
240
-
Because attachments are stored on their bases by type, there can only be one attachment of each type present on a value at a time.
241
-
Cadence will raise a runtime error if a user attempts to add an attachment to a value when one it already exists on that value.
242
-
The type returned by the `attach` expression is the same type as the expression on the right-hand side of the `to`;
243
-
attaching an attachment to a value does not change its type.
202
+
Because attachments are stored on their bases by type, there can only be one attachment of each type present on a value at a time. Cadence will raise a runtime error if a user attempts to add an attachment to a value when one already exists on that value. The type returned by the `attach` expression is the same type as the expression on the right-hand side of the `to`; attaching an attachment to a value does not change its type.
244
203
245
-
## Accessing Attachments
204
+
## Accessing attachments
246
205
247
-
Attachments are accessed on composites via type-indexing:
248
-
composite values function like a dictionary where the keys are types and the values are attachments.
249
-
So given a composite value `v`, one can look up the attachment named `A` on `v` using indexing syntax:
206
+
Attachments are accessed on composites via type-indexing: composite values function like a dictionary where the keys are types and the values are attachments. So, given a composite value `v`, one can look up the attachment named `A` on `v` using an indexing syntax:
250
207
251
208
```cadence
252
209
let a = v[A] // has type `&A?`
253
210
```
254
211
255
-
This syntax requires that `A` is a nominal attachment type,
256
-
and that `v` has a composite type that is a subtype of `A`'s declared base type.
257
-
As mentioned above, attachments are not first-class values,
258
-
so this indexing returns a reference to the attachment on `v`, rather than the attachment itself.
259
-
If the attachment with the given type does not exist on `v`, this expression returns `nil`.
212
+
This syntax requires that `A` is a nominal attachment type, and that `v` has a composite type that is a subtype of `A`'s declared base type. As mentioned above, attachments are not first-class values, so this indexing returns a reference to the attachment on `v`, rather than the attachment itself. If the attachment with the given type does not exist on `v`, this expression returns `nil`.
260
213
261
-
The set of entitlements to which the result of an attachment access is authorized is the same as the set of entitlements to which the base
262
-
value is authorized. So, for example, given the following definition for `A`:
214
+
The set of entitlements to which the result of an attachment access is authorized is the same as the set of entitlements to which the base value is authorized. So, for example, given the following definition for `A`:
263
215
264
216
```cadence
265
217
entitlement E
@@ -289,33 +241,30 @@ attachment A for R {
289
241
let a = v[A]!
290
242
```
291
243
292
-
When `v` has type `&R`, the resulting type of `a` will be an unauthorized `&A`.
293
-
Contrarily, if `v` has type `auth(E) &R`, then the type of `a` will be authorized to the same: `auth(E) &A`.
294
-
Finally, when `v` is not a reference (i.e. an owned value of type `R`), then `a` will be "fully entitled" to `A`; it will be granted
295
-
all the entitlements mentioned by `A`, i.e. in this case it will have type `auth(E, F) &A`.
244
+
When `v` has type `&R`, the resulting type of `a` will be an unauthorized `&A`. Contrarily, if `v` has type `auth(E) &R`, then the type of `a` will be authorized to the same: `auth(E) &A`. Finally, when `v` is not a reference (i.e., an owned value of type `R`), then `a` will be "fully entitled" to `A`; it will be granted all the entitlements mentioned by `A`, i.e., in this case, it will have type `auth(E, F) &A`.
296
245
297
-
This is roughly equivalent to the behavior of the `Identity`[entitlement mapping](./access-control.md#entitlement-mappings); indeed, attachments can be thought of
298
-
as being `Identity`-mapped fields on their base value.
246
+
This is roughly equivalent to the behavior of the `Identity`[entitlement mapping]; indeed, attachments can be thought of as being `Identity`-mapped fields on their base value.
299
247
300
-
## Removing Attachments
248
+
## Removing attachments
301
249
302
-
Attachments can be removed from a value with a `remove` statement.
303
-
The statement consists of the `remove` keyword, the nominal type for the attachment to be removed,
304
-
the `from` keyword, and the value from which the attachment is meant to be removed.
250
+
Attachments can be removed from a value with a `remove` statement. The statement consists of the `remove` keyword, the nominal type for the attachment to be removed, the `from` keyword, and the value from which the attachment is meant to be removed.
305
251
306
252
The value on the right-hand side of `from` must be a composite value whose type is a subtype of the attachment type's declared base.
307
253
308
-
E.g., to remove an `A` attachment from some resource `r` whose type supports that attachment:
254
+
For example, to remove an `A` attachment from some resource `r` whose type supports that attachment:
309
255
310
256
```cadence
311
257
remove A from r
312
258
```
313
259
314
-
After the statement executes, the composite value on the right-hand side of `from` will no longer contain the attachment.
315
-
If the value does not contain the attachment that appears after the `remove` keyword, this statement has no effect.
260
+
After the statement executes, the composite value on the right-hand side of `from` will no longer contain the attachment. If the value does not contain the attachment that appears after the `remove` keyword, this statement has no effect.
261
+
262
+
Attachments can be removed from a type in any order, so developers should take care not to design any attachments that rely on specific behaviors of other attachments, as there is no requirement that an attachment depend on another or that a type has a given attachment when another attachment is present.
263
+
264
+
If a resource containing attachments is `destroy`ed, all of its attachments will be `destroy`ed in an arbitrary order.
316
265
317
-
Attachments may be removed from a type in any order,
318
-
so users should take care not to design any attachments that rely on specific behaviors of other attachments,
319
-
as there is no to require that an attachment depend on another or to require that a type has a given attachment when another attachment is present.
266
+
<!--Relativelinks.Willnotrenderonthepage-->
320
267
321
-
If a resource containing attachments is `destroy`ed, all its attachments will be `destroy`ed in an arbitrary order.
0 commit comments