Skip to content

Commit d11a23e

Browse files
authored
Merge pull request #239 from onflow/attachments
Edit Imports and Attachments articles
2 parents b55ad07 + aa5db87 commit d11a23e

2 files changed

Lines changed: 52 additions & 105 deletions

File tree

docs/language/attachments.mdx

Lines changed: 44 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,13 @@ title: Attachments
33
sidebar_position: 17
44
---
55

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.
97

10-
## Declaring Attachments
8+
## Declaring attachments
119

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:
1513

1614
```cadence
1715
access(all)
@@ -28,34 +26,19 @@ attachment Baz for MyInterface: MyOtherInterface {
2826
}
2927
```
3028

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.
3230

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.
3732

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.
4234

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.
4836

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.
5138

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`.
5740

58-
So, for example, this would be a valid declaration of an attachment:
41+
For example, this is a valid declaration of an attachment:
5942

6043
```
6144
access(all)
@@ -87,14 +70,9 @@ attachment A for R {
8770
base.foo()
8871
}
8972
}
90-
9173
```
9274

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.
9876

9977
```cadence
10078
access(all)
@@ -130,9 +108,9 @@ attachment SomeAttachment for SomeContract.SomeStruct {
130108
}
131109
```
132110

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:
136114

137115
```cadence
138116
resource R {
@@ -151,9 +129,10 @@ attachment A for R {
151129
}
152130
```
153131

154-
while this would not:
132+
While this does **not** work:
155133

156134
```cadence
135+
// Bad code example. Do not use.
157136
resource R {
158137
access(E)
159138
fun foo() {
@@ -172,32 +151,19 @@ attachment A for R {
172151
}
173152
```
174153

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).
178155

179-
### Attachment Types
156+
### Attachment types
180157

181158
An attachment declared with `access(all) attachment A for C { ... }` will have a nominal type `A`.
182159

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.
187161

188-
## Creating Attachments
162+
## Creating attachments
189163

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.
197165

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:
201167

202168
```cadence
203169
access(all)
@@ -215,11 +181,7 @@ let r <- create R()
215181
let r2 <- attach A(x: 3) to <-r
216182
```
217183

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:
223185

224186

225187
```cadence
@@ -237,29 +199,19 @@ let r <- create R() // has type @R
237199
let r2 <- attach A() to <-r // ok, because `R` is a subtype of `I`, still has type @R
238200
```
239201

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.
244203

245-
## Accessing Attachments
204+
## Accessing attachments
246205

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:
250207

251208
```cadence
252209
let a = v[A] // has type `&A?`
253210
```
254211

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`.
260213

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`:
263215

264216
```cadence
265217
entitlement E
@@ -289,33 +241,30 @@ attachment A for R {
289241
let a = v[A]!
290242
```
291243

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`.
296245

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.
299247

300-
## Removing Attachments
248+
## Removing attachments
301249

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.
305251

306252
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.
307253

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:
309255

310256
```cadence
311257
remove A from r
312258
```
313259

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.
316265

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+
<!-- Relative links. Will not render on the page -->
320267

321-
If a resource containing attachments is `destroy`ed, all its attachments will be `destroy`ed in an arbitrary order.
268+
[access control]: ./access-control.md
269+
[entitlement mapping]: ./access-control.md#entitlement-mappings
270+
[accessing attachments]: #accessing-attachments

0 commit comments

Comments
 (0)