# Another Update on Stable Cadence

**URL:** https://forum.flow.com/t/another-update-on-stable-cadence/3715
**Category:** 🏄🏻‍♀️ Cadence
**Created:** [October 14, 2022, 8:29pm UTC](https://forum.flow.com/t/another-update-on-stable-cadence/3715 "2022-10-14T20:29:57Z")
**Posts on this page:** 4
**Page:** 1

<div class="post-metadata">

### Author: ![bastian](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/bastian/32/183_2.png) [@bastian](https://forum.flow.com/u/bastian)
#### Post date: [October 14, 2022, 8:29pm UTC](https://forum.flow.com/t/another-update-on-stable-cadence/3715/1 "2022-10-14T20:29:58Z")

</div>

In January 2022 the Cadence team shared their thoughts on [the path to “Stable Cadence”](http://forum.flow.com/t/the-path-to-stable-cadence/2702). We have come a long way since: We have released the [Secure Cadence milestone](https://permissionless.onflow.org/), which enabled permissionless deployment, while we continued working on the Stable Cadence milestone and other language features and improvements.

In this post we would like to update everyone on the progress that has been made with the amazing Flow development community on the Stable Cadence milestone so far, what you can expect when it is released around mid-next year, and how you can start preparing for it.

We would also like to thank all community members that are active and contribute – it would be much harder without you!

* * *

# 🏁 Ready/Merged

## View Functions / Function Calls in Conditions

> **Click here to read more**
>
> - [https://github.com/onflow/flow/pull/1056](https://github.com/onflow/flow/pull/1056)
> - [https://github.com/onflow/cadence/pull/1871](https://github.com/onflow/cadence/pull/1871)
> 
> Cadence has added support for annotating functions with the `view` keyword, which enforces that no “mutating” operations occur inside the body of the function. The `view` keyword is placed before the `fun` keyword in the declaration.
> 
> If a function has no `view` annotation, it is considered “non-view”, and users should encounter no difference in behavior in these functions from what they are used to. If a function does have a `view` annotation, then the following operations are not allowed:
> 
> - Writing to, modifying or destroying any resources
> - Writing to or modifying any references
> - Assigning to or modifying any variables that cannot be determined to have been created locally inside of the `view` function in question. In particular, this means that captured and global variables cannot be written in these functions
> - Emitting an event
> - Calling any non-`view` function
> 
> Additionally, function preconditions and post-conditions are now considered `view` contexts; meaning that any operations that would be prevented inside of a `view` function are also not permitted in a pre or post-condition. This is to prevent underhanded code wherein a user modifies global or contract state inside of a condition, where they are meant to simply be asserting properties of that state. In particular, since only expressions were permitted inside conditions already, this means that if users wish to call any functions in conditions, these functions must now be made `view` functions.

## Missing or Incorrect Argument Labels Not Reported

> **Click here to read more**
>
> - [https://github.com/onflow/cadence/pull/1717](https://github.com/onflow/cadence/pull/1717)
> - [https://github.com/onflow/cadence/pull/2013](https://github.com/onflow/cadence/pull/2013)
> 
> Function calls with missing or incorrect argument labels were previously not reported as an error.  
> Such incorrect function calls are now an error and should be fixed by providing the expected argument labels.
> 
> For example:
> 
> ```auto
> // Contract "TestContract" deployed at address 0x1
> 
> pub contract TestContract {
> pub struct TestStruct {
> pub let a: Int
> pub let b: String
> init(first: Int, second: String) {
> self.a = first
> self.b = second
> }
> }
> }
> 
> ```
> 
> **Incorrect** program:
> 
> The initializer of `TestContract.TestStruct` expects the argument labels `first` and `second`.
> 
> However, the call of the initializer provides the incorrect argument label `wrong` for the first argument, and is missing the label for the second argument.
> 
> ```auto
> // Script
> import TestContract from 0x1
> 
> pub fun main() {
> TestContract.TestStruct(wrong: 123, "abc")
> }
> 
> ```
> 
> This now results in the following errors:
> 
> ```auto
> error: incorrect argument label
> --> script:4:34
> |
> 4 | TestContract.TestStruct(wrong: 123, "abc")
> | ^^^^^ expected `first`, got `wrong`
> 
> error: missing argument label: `second`
> --> script:4:46
> |
> 4 | TestContract.TestStruct(wrong: 123, "abc")
> | ^^^^^
> 
> ```
> 
> **Corrected** program:
> 
> ```auto
> // Script
> import TestContract from 0x1
> 
> pub fun main() {
> TestContract.TestStruct(first: 123, second: "abc")
> }
> 
> ```
> 
> We would like to thank community member justjoolz for reporting this bug.

## Incorrect Operator in Reference Expressions Not Reported

> **Click here to read more**
>
> - [https://github.com/onflow/cadence/pull/1661](https://github.com/onflow/cadence/pull/1661)
> - [https://github.com/onflow/cadence/pull/2010](https://github.com/onflow/cadence/pull/2010)
> 
> The syntax for reference expressions is `&v as &T`, which represents taking a reference to value `v` as type `T`.
> 
> Reference expressions with other incorrect operators such as `as?` and `as!` were previously not reported as an error.  
> Such incorrect reference expressions are now an error and should be fixed by using the `as` operator.
> 
> For example:
> 
> **Incorrect** program:
> 
> The reference expression uses the incorrect operator `as!`.
> 
> ```auto
> let number = 1
> let ref = &number as! &Int
> 
> ```
> 
> This now results in the following error:
> 
> ```auto
> error: cannot infer type from reference expression: requires an explicit type annotation
> --> test:3:17
> |
> 3 | let ref = &number as! &Int
> | ^
> 
> ```
> 
> **Corrected** program:
> 
> ```auto
> let number = 1
> let ref = &number as &Int
> 
> ```
> 
> Alternatively, the same code can now also be written as follows:
> 
> ```auto
> let number = 1
> let ref: &Int = &number
> 
> ```

## Identifiers cannot be keywords in most cases

> **Click here to read more**
>
> [https://github.com/onflow/cadence/pull/1937](https://github.com/onflow/cadence/pull/1937)
> 
> Previously, we allowed keywords (e.g. `continue`, `for`, etc.) to be used in identifier position. For example, the following program was allowed by the parser.
> 
> ```swift
> pub fun continue(import: Int, break: String) {...}
> 
> ```
> 
> This led to a lot of ambiguities, so the consensus was to disallow most keywords from being used as names. After a careful review of the language grammar, we currently designate the following keywords as “soft”, meaning that they’re still allowed to be used as identifiers due to having limited significance within the language. These allowed keywords are as follows:
> 
> - `from`: only used in import statements `import foo from ...`
> - `account`: used in access modifiers `access(account) let ...`
> - `set`: used in access modifier `pub(set) var globalMutVar = ...`
> - `all`: used in access modifier `access(all) let ...`
> 
> Any other keywords will raise an error during parsing, such as:
> 
> ```swift
> let break: Int = 0
> // error: expected identifier after start of variable declaration, got keyword break
> 
> ```
> 
> Migrating contracts to Stable Cadence is a matter of renaming any identifiers that clash with reserved keywords. For instance, `let contract` → `let nftContract`, etc.

## Result of `toBigEndianBytes()` for `U?Int(128|256)` changed

> **Click here to read more**
>
> [https://github.com/onflow/cadence/pull/1917](https://github.com/onflow/cadence/pull/1917)
> 
> The previous implementation of `.toBigEndianBytes()` was incorrect for the large integer types:
> 
> - `Int128`
> - `Int256`
> - `UInt128`
> - `UInt256`
> 
> Calling `.toBigEndianBytes()` on smaller sized integer types usually returns the exact number of bytes that fit into the parent type, left-padded with zeros. For instance, `(x: Int64).toBigEndianBytes()` returns an array of 8 bytes. These larger types erroneously returned variable-length byte arrays without padding, enough to store their highest set bit. This was inconsistent with the smaller fixed-size numeric types, such as `Int8`, and `Int32`. To fix this inconsistency, `Int128` and `UInt128` now always return arrays of 16 bytes, while `Int256` and `UInt256` return 32 bytes.
> 
> ```swift
> let someNum: UInt128 = 123456789
> let someBytes: [UInt8] = someNum.toBigEndianBytes()
> // old behaviour:
> // someBytes = [7, 91, 205, 21]
> // new behaviour:
> // someBytes = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 91, 205, 21] 
> 
> ```
> 
> If your contract relied on the previous behaviour of truncating the leading zeros, the arbitrary-precision `Int` and `UInt` types retain variable-length byte representations. The old behaviour can be recovered by first converting to a variable-length type, for example:
> 
> ```swift
> let someNum: UInt128 = 123456789
> let someBytes: [UInt8] = UInt(someNum).toBigEndianBytes()
> // someBytes = [7, 91, 205, 21]
> 
> ```

## Deprecated key management API got removed

> **Click here to read more**
>
> [https://github.com/onflow/cadence/pull/1842](https://github.com/onflow/cadence/pull/1842)
> 
> The first account key management API, which was deprecated last year, was removed. Instead, the new key management API should be used:
> 
> | Removed | Replacement |
> | --- | --- |
> | AuthAccount.addPublicKey | AuthAccount.keys.add |
> | AuthAcount.removePublicKey | AuthAccount.keys.revoke |
> 
> For more information, please refer to the [documentation](https://developers.flow.com/cadence/language/accounts#account-keys).

## Resource tracking for optional binding

> **Click here to read more**
>
> [https://github.com/onflow/cadence/pull/2044](https://github.com/onflow/cadence/pull/2044)
> 
> Resource tracking for optional bindings (”if-let statements”) was implemented incorrectly and fixed. This may affect existing code that relied on the incorrect behaviour.
> 
> For example, the following program used to be invalid, reporting a resource loss error for `optR`:
> 
> ```jsx
> resource R {}
>           
> fun asOpt(_ r: @R): @R? {          
> return <-r          
> }
>           
> fun test() {
> let r <- create R()
> let optR <- asOpt(<-r)
> if let r2 <- optR {
> destroy r2
> }
> }
> 
> ```
> 
> This program is now considered valid.
> 
> However, programs that previously resolved the incorrect resource loss error, for example by invalidating the resource also in the else-branch or after the if-statement, are now invalid:
> 
> ```jsx
> fun test() {
> let r <- create R()
> let optR <- asOpt(<-r)
> if let r2 <- optR {
> destroy r2
> } else {
> destroy optR
> }
> }
> 
> ```

## Improved definite return analysis

> **Click here to read more**
>
> [https://github.com/onflow/cadence/pull/2090](https://github.com/onflow/cadence/pull/2090)
> 
> Definite return analysis determines if a function exited, e.g. through a `return` statement, or by calling a function that never returns, like `panic`.
> 
> This analysis was improved in Stable Cadence.
> 
> This means that the following program is now accepted: both branches of the if-statement exit, one using a `return` statement, the other using a function that never returns, `panic`:
> 
> ```swift
> resource R {}
> 
> fun mint(id: UInt64): @R {
> if id > 100 {
> return <- create R()
> } else {
> panic("bad id")
> }
> }
> 
> ```
> 
> However, this also means that some programs that were previously accepted are now being rejected.
> 
> For example, the program above was previously rejected with a “missing return statement” error – even though we can convince ourselves that the function will exit in both branches of the if-statement, and that any code after the if-statement is unreachable, the type checker was not able to detect that – it now does.
> 
> As a workaround, a developer might have previously added an additional exit at the end of the function:
> 
> ```swift
> resource R {}
> 
> fun mint(id: UInt64): @R {
> if id > 100 {
> return <- create R()
> } else {
> panic("bad id")
> }
> 
> // added to avoid "missing return statement"
> panic("unreachable")
> }
> 
> ```
> 
> The improved type checker now detects and reports the unreachable code after the if-statement as an error:
> 
> ```swift
> error: unreachable statement
> --> test.cdc:12:4
> |
> 12 | panic("unreachable")
> | ^^^^^^^^^^^^^^^^^^^^
> exit status 1
> 
> ```
> 
> To make the code valid, simply remove the unreachable code.

* * *

# 🧭 Upcoming

The following changes _may_ get included in Stable Cadence. Details and decisions are still outstanding.

## The Capability API may get replaced by an improved one

> **Click here to read more**
>
> - [https://github.com/onflow/flow/pull/798](https://github.com/onflow/flow/pull/798)
> 
> A FLIP proposes replacing the existing capability API with one which is more powerful and easier to use. The private storage domain will be removed, creating new capabilities will be simpler, revocation of capabilities will be more straightforward. This will not change how capabilities are consumed/used, only how they are created. Any code calling `AuthAccount::(un)link` will need to change.

## References to resource-kinded values may get invalidated when the referenced value is transferred

> **Click here to read more**
>
> - [https://github.com/onflow/flow/pull/1043](https://github.com/onflow/flow/pull/1043)
> - [https://github.com/onflow/cadence/pull/2037](https://github.com/onflow/cadence/pull/2037)
> - [https://github.com/onflow/cadence/pull/1999](https://github.com/onflow/cadence/pull/1999)
> 
> Previously, when a reference is taken to a resource, that reference remains valid even if the resource was transferred. In other words, references stay alive forever. This could be a potential foot-gun, where one could gain/give/retain unintended access to resources through references.
> 
> With this change, references are invalidated if the underlying resource is transferred after the reference was taken. The reference is invalidated upon the first transfer, regardless of the origin and the destination.
> 
> e.g:
> 
> ```rust
> // Create a resource.
> let r <-create R()
> 
> // And take a reference.
> let ref = &r as &R
> 
> // Then transfer the resource into an account.
> account.save(<-r, to: /storage/r)
> 
> // Update the reference.
> ref.id = 2
> 
> ```
> 
> Old behaviour:
> 
> ```rust
> // This will also update the referenced resource in the account.
> ref.id = 2
> 
> ```
> 
> New behaviour:
> 
> ```rust
> // Trying to update/access the reference will produce a static error:
> // "invalid reference: referenced resource may have been moved or destroyed"
> ref.id = 2
> 
> ```
> 
> However, not all scenarios can be detected statically. e.g:
> 
> ```rust
> pub fun test(ref: &R) {
> ref.id = 2
> }
> 
> ```
> 
> In above function, it is not possible to determine whether the resource to which the reference was taken has been moved or not. Therefore, such cases are checked at run-time, and a run-time error will occur if the resource has been moved.

## Nested type requirements may get limited to just events

> **Click here to read more**
>
> [Nested Type Requirements](https://developers.flow.com/cadence/language/interfaces#nested-type-requirements) are currently supported for all kinds of [composite types](https://developers.flow.com/cadence/language/composite-types).
> 
> A future proposal may limit support to just events.
> 
> [Nested Type Requirements](https://docs.onflow.org/cadence/language/interfaces/#nested-type-requirements) are a fairly advanced concept. Just like an interface may  
> require a conforming type to provide a certain field or function, it may also require the conforming type to provide a nested type. This is uncommon in other programming languages and hard to understand. In addition, the value of nested type requirements was never realized.

## Language support for preventing re-entrancy attacks may get introduced

> **Click here to read more**
>
> A future proposal may introduce additional language features and possibly change existing language semantics to allow developers to automatically or at least more easily prevent re-entrancy attacks.

## Restrictions to external mutation may get added

> **Click here to read more**
>
> It is currently possible to mutate fields with mutable values from outside the containing type.
> 
> A future proposal may restrict this.

## Semantics for variables in for-loop statements may change

> **Click here to read more**
>
> [https://github.com/onflow/flips/pull/13](https://github.com/onflow/flips/pull/13)
> 
> A FLIP proposes to change the behaviour of variables in for-loop statements. This will remove an often surprising behaviour from the language and reduce the likelihood of bugs. This change will only affect few programs, as the behaviour change is only noticeable if the program captures the for-loop statement variables in a function value (closure).
> 
> ```swift
> // Capture the values of the array [1, 2, 3]
> let fs: [((): Int)] = []
> for x in [1, 2, 3] {
> // Create a list of functions that return the array value
> fs.append(fun (): Int {
> return x
> })
> }
> 
> // Evaluate each function and gather all array values 
> let values: [Int] = [] 
> for f in fs {
> values.append(f())
> }
> 
> ```
> 
> Previously, `values` would result in `[3, 3, 3]`, which might be surprising and unexpected. This is because currently `x` is _reassigned_ the current array element on each iteration, leading to each function in `fs` returning the last element of the array.
> 
> If the proposed change gets approved and implemented, `values` will result in `[1, 2, 3]`, which is likely what the author of the program expected.

* * *

# ➡ Related

## FT / NFT Standard changes (Still WIP)

> **Click here to read more**
>
> The Fungible Token and Non-Fungible Token Standard interfaces are being upgraded to allow for multiple tokens per contract, fix some issues with the original standards, and introduce other various improvements suggested by the community.
> 
> - Original Proposal: [http://forum.flow.com/t/streamlined-token-standards-proposal/3075](http://forum.flow.com/t/streamlined-token-standards-proposal/3075)
> - Fungible Token Changes PR: [https://github.com/onflow/flow-ft/pull/77](https://github.com/onflow/flow-ft/pull/77)
> - NFT Changes PR: [https://github.com/onflow/flow-nft/pull/126](https://github.com/onflow/flow-nft/pull/126)
> 
> The changes and the FLIP are still a work in progress, so the expected actions that developers will need to take are not yet finalized, but it will involve upgrading your token contracts with changes to events, function signatures, resource interface conformances, and other small changes. More examples coming soon.

---

<div class="post-metadata">

### Author: ![bastian](https://sea2.discourse-cdn.com/flex022/user_avatar/forum.flow.com/bastian/32/183_2.png) [@bastian](https://forum.flow.com/u/bastian)
#### Post date: [October 14, 2022, 8:30pm UTC](https://forum.flow.com/t/another-update-on-stable-cadence/3715/2 "2022-10-14T20:30:33Z")

</div>



---

<div class="post-metadata">

### Author: ![jane2](https://avatars.discourse-cdn.com/v4/letter/j/eada6e/32.png) [@jane2](https://forum.flow.com/u/jane2)
#### Post date: [August 25, 2023, 5:19pm UTC](https://forum.flow.com/t/another-update-on-stable-cadence/3715/3 "2023-08-25T17:19:10Z")

</div>

Thank You.

---

<div class="post-metadata">

### Author: ![jane](https://avatars.discourse-cdn.com/v4/letter/j/ecb155/32.png) [@jane](https://forum.flow.com/u/jane)
#### Post date: [August 25, 2023, 5:19pm UTC](https://forum.flow.com/t/another-update-on-stable-cadence/3715/4 "2023-08-25T17:19:14Z")

</div>

Thank you for update
