Skip to content

Commit

Permalink
Merge pull request #34 from onflow/sainati/misc-improvements
Browse files Browse the repository at this point in the history
Misc documentation improvements
  • Loading branch information
dsainati1 authored Dec 22, 2023
2 parents 7a647fe + cae7c9a commit 26c68e8
Show file tree
Hide file tree
Showing 5 changed files with 123 additions and 112 deletions.
3 changes: 2 additions & 1 deletion versioned_docs/version-1.0/language/access-control.md
Original file line number Diff line number Diff line change
Expand Up @@ -321,7 +321,8 @@ Owned values are not affected by entitled declarations.
Entitlement mappings are a way to statically declare how entitlements are propagated
from parents to child objects in a nesting hierarchy.

When objects have fields that are child objects,
When objects have fields that are child objects,
entitlement mappings can be used
to grant access to the inner object based on the entitlements of the reference to the parent object.

Consider the following example,
Expand Down
18 changes: 10 additions & 8 deletions versioned_docs/version-1.0/language/attachments.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,6 @@ title: Attachments
sidebar_position: 21
---

<Callout type="warning">
⚠️ This section describes a feature that is not yet released on Mainnet.
</Callout>

Attachments are a feature of Cadence designed to allow developers to extend a struct or resource type
(even one that they did not declare) with new functionality,
without requiring the original author of the type to plan or account for the intended behavior.
Expand Down Expand Up @@ -41,15 +37,15 @@ while in the case of an interface the attachment is usable on any type that conf
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-kinded attachments may have resource members,
and such members must be explicitly handled in the `destroy` function.
Only resource-kinded attachments may have resource members.

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` like in other composite declarations.
The specific entitlements that this reference has depends on the access modifier associated with the member function in which the `self` reference
appears, and is explained in more detail below.

If a resource with attachments on it is `destroy`ed, the `destroy` functions of all its attachments are all run in an unspecified order.
If a resource with attachments on it is `destroy`ed, all 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.

Within the body of an attachment, there is also a `base` keyword available,
Expand Down Expand Up @@ -267,8 +263,14 @@ the `from` keyword, and the value from which the attachment is meant to be remov

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.

E.g., to remove an `A` attachment from some resource `r` whose type supports that attachment:

```cadence
remove A from r
```

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 `t`, this statement has no effect.
If the value does not contain the attachment that appears after the `remove` keyword, this statement has no effect.

Attachments may be removed from a type in any order,
so users should take care not to design any attachments that rely on specific behaviors of other attachments,
Expand Down
2 changes: 1 addition & 1 deletion versioned_docs/version-1.0/language/composite-types.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -116,7 +116,7 @@ The initializer is declared using the `init` keyword.

The initializer always follows any fields.

There are three kinds of fields:
There are two kinds of fields:

- **Constant fields** are also stored in the composite value,
but after they have been initialized with a value
Expand Down
210 changes: 109 additions & 101 deletions versioned_docs/version-1.0/language/functions.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -14,8 +14,8 @@ This behavior is often called "first-class functions".
## Function Declarations

Functions can be declared by using the `fun` keyword, followed by the name of the declaration,
the parameters, the optional return type,
and the code that should be executed when the function is called.
the parameters, the optional return type,
and the code that should be executed when the function is called.

The parameters need to be enclosed in parentheses.
The return type, if any, is separated from the parameters by a colon (`:`).
Expand Down Expand Up @@ -224,103 +224,6 @@ let double =
}
```

## View Functions

Functions can be annotated as `view` to indicate that they do not modify any external state or any account state.
A `view` annotation can be added to the beginning of a function declaration or expression like so:

```cadence
view access(all) fun foo(): Void {}
let x = view fun(): Void {}
access(all) struct S {
view access(all) fun foo(): Void {}
view init()
}
```

All functions that do not have a `view` annotation are considered non-view,
and cannot be called inside of `view` contexts,
like inside of a `view` function or in a precondition or postcondition.

Function types can also have `view` annotations,
to be placed after the opening parenthesis but before the parameter list.
So, for example, these are valid types:

```cadence
let f: view fun (Int): Int = ...
let h: view fun (): (view fun (): Void) = ...
```

Any function types without a `view` annotation will be considered non-view.

Functions are covariant with respect to `view` annotations,
so a `view` function is a subtype of an non-view function with the same parameters and return types.
So, the following declarations would typecheck:

```cadence
let a: view fun (): Void = view fun() {}
let b: fun (): Void = view fun() {}
let c: fun (): Void = fun() {}
let d: fun(view fun(): Void): Void = fun (x: fun(): Void) {} // contravariance
```

while these would not:


```cadence
let x: view fun (): Void = fun() {}
let y: fun(fun(): Void): Void = fun(f: view fun(): Void) {} // contravariance
```

The operations that are not permitted in `view` contexts are:

* Calling a non-view function (including any functions that modify account state or storage like `save` or `load`)
* Writing to or modifying any resources
* Writing to or modifying any references
* Indexed assignment or writes to any variables not statically knowable to have been defined in the current function's scope,
or to any resources or references

So, for example, this code would be allowed:

```cadence
view fun foo(): Int {
let a: [Int] = []
a[0] = 3
return a.length
}
```

while this would not:

```cadence
let a: [Int] = []
view fun foo(): Int {
a[0] = 3
return a.length
}
```

A caveat to this is that in some cases a non-`view` function that only performs a mutation that would be allowed in a `view` context will be rejected as a limitation of the analysis.
In particular, users may encounter this with arrays or dictionaries, where a function like:

```cadence
view fun foo(): Int {
let a: [Int] = [0]
a[0] = 1
}
```

is acceptable, because `a` is local to this function, while

```cadence
view fun foo(): Int {
let a: [Int] = [0]
a.append(1)
}
```

will be rejected, because `append` is not `view`.

## Function Calls

Functions can be called (invoked). Function calls
Expand All @@ -346,12 +249,13 @@ double()

## Function Types

Function types consist of the function's parameter types
Function types consist of the `fun` keyword, the function's parameter types
and the function's return type.

The parameter types need to be enclosed in parentheses,
followed by a colon (`:`), and end with the return type.
The whole function type needs to be enclosed in parentheses.

Optionally, the `view` keyword can be included before the `fun` keyword to indicate that the type is that of a `view` function.

```cadence
// Declare a function named `add`, with the function type `fun(Int, Int): Int`.
Expand Down Expand Up @@ -581,6 +485,110 @@ Both preconditions and postconditions are considered [`view` contexts](#view-fun
any operations that are not legal in functions with `view` annotations are also not allowed in conditions.
In particular, this means that if you wish to call a function in a condition, that function must be `view`.

## View Functions

Functions can be annotated as `view` to indicate that they do not modify any external state or any account state.
A `view` annotation can be added to the beginning of a function declaration or expression like so:

```cadence
access(all)
view fun foo(): Void {}
let x = view fun(): Void {}
access(all)
struct S {
access(all)
view fun foo(): Void {}
view init()
}
```

All functions that do not have a `view` annotation are considered non-view,
and cannot be called inside of `view` contexts,
like inside of a `view` function or in a precondition or postcondition.

Function types can also have `view` annotations,
to be placed after the opening parenthesis but before the parameter list.
So, for example, these are valid types:

```cadence
let f: view fun (Int): Int = ...
let h: view fun (): (view fun (): Void) = ...
```

Any function types without a `view` annotation will be considered non-view.

Functions are covariant with respect to `view` annotations,
so a `view` function is a subtype of an non-view function with the same parameters and return types.
So, the following declarations would typecheck:

```cadence
let a: view fun (): Void = view fun() {}
let b: fun (): Void = view fun() {}
let c: fun (): Void = fun() {}
let d: fun(view fun(): Void): Void = fun (x: fun(): Void) {} // contravariance
```

while these would not:


```cadence
let x: view fun (): Void = fun() {}
let y: fun(fun(): Void): Void = fun(f: view fun(): Void) {} // contravariance
```

The operations that are not permitted in `view` contexts are:

* Calling a non-view function (including any functions that modify account state or storage like `save` or `load`)
* Writing to or modifying any resources
* Writing to or modifying any references
* Indexed assignment or writes to any variables not statically knowable to have been defined in the current function's scope,
or to any resources or references

So, for example, this code would be allowed:

```cadence
view fun foo(): Int {
let a: [Int] = []
a[0] = 3
return a.length
}
```

while this would not:

```cadence
let a: [Int] = []
view fun foo(): Int {
a[0] = 3
return a.length
}
```

A caveat to this is that in some cases a non-`view` function that only performs a mutation that would be allowed in a `view` context will be rejected as a limitation of the analysis.
In particular, users may encounter this with arrays or dictionaries, where a function like:

```cadence
view fun foo(): Int {
let a: [Int] = [0]
a[0] = 1
}
```

is acceptable, because `a` is local to this function, while

```cadence
view fun foo(): Int {
let a: [Int] = [0]
a.append(1)
}
```

will be rejected, because `append` is not `view`.

## Functions are Values

Functions are values ("first-class"), so they may be assigned to variables and fields
Expand Down
2 changes: 1 addition & 1 deletion versioned_docs/version-1.0/language/resources.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -337,7 +337,7 @@ event ResourceDestroyed(field1: T1 = e1, field2: T2 = e2, ...)

The value of `field1` on the event will be the result of evaluating `e1` before destroying the resource,
the value of `field2` on the event will be the result of evaluating `e2` before destroying the resource,
and so on. As one might expect, `e1` and `e2` must also expressions of type `T1` and `T2` respectively.
and so on. As one might expect, `e1` and `e2` must also be expressions of type `T1` and `T2` respectively.

In order to guarantee that these events can be emitted with no chance of failure at runtime, there are restrictions
placed on which kinds of types and expressions can be used in their definitions. In general, an expression
Expand Down

0 comments on commit 26c68e8

Please sign in to comment.