From 4e14d3d64b13cb5e3fc91a7e3caa181d874a67b1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:43:46 -0700 Subject: [PATCH 01/11] document casting operators on operators page --- docs/language/operators.md | 115 +++++++++++++++++++++++++++++ docs/language/values-and-types.mdx | 50 +------------ 2 files changed, 116 insertions(+), 49 deletions(-) diff --git a/docs/language/operators.md b/docs/language/operators.md index 0cfd8e7779..0b47bbec6c 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -440,6 +440,121 @@ let y = 1 > 2 ? nil : 3 // `y` is `3` and has type `Int?` ``` +## Casting Operators + +### Static Casting Operator + +The static casting operator `as` can be used to statically type cast a value to a type. + +If the static type of the value is a subtype of the given type that should be casted to, +the operator returns the value as the given type. + +The cast is performed statically, i.e. when the program is type-checked. +Only the static type of the value is considered, not the run-time type of the value. + +This means it is not possible to downcast using this operator. +Consider using the [conditional downcasting operator `as?`](#conditional-downcasting-operator) instead. + +```cadence +// Declare a constant named `integer` which has type `Int`. +// +let integer: Int = 1 + +// Statically cast the value of `integer` to the supertype `Number`. +// The cast succeeds, because the type of the variable `integer`, +// the type `Int`, is a subtype of type `Number`. +// This is an upcast. +// +let number = integer as Number +// `number` is `1` and has type `Number` + +// Declare a constant named `something` which has type `AnyStruct`, +// with an initial value which has type `Int`. +// +let something: AnyStruct = 1 + +// Statically cast the value of `something` to `Int`. +// This is invalid, the cast fails, because the static type of the value is type `AnyStruct`, +// which is not a subtype of type `Int`. +// +let result = something as Int +``` + +### Conditional Downcasting Operator + +The conditional downcasting operator `as?` can be used to dynamically type cast a value to a type. +The operator returns an optional. +If the value has a run-time type that is a subtype of the given type that should be casted to, +the operator returns the value as the given type, +otherwise the result is `nil`. + +The cast is performed at run-time, i.e. when the program is executed, +not statically, i.e. when the program is checked. + +```cadence +// Declare a constant named `something` which has type `AnyStruct`, +// with an initial value which has type `Int`. +// +let something: AnyStruct = 1 + +// Conditionally downcast the value of `something` to `Int`. +// The cast succeeds, because the value has type `Int`. +// +let number = something as? Int +// `number` is `1` and has type `Int?` + +// Conditionally downcast the value of `something` to `Bool`. +// The cast fails, because the value has type `Int`, +// and `Bool` is not a subtype of `Int`. +// +let boolean = something as? Bool +// `boolean` is `nil` and has type `Bool?` +``` + +Downcasting works for nested types (e.g. arrays), +interfaces (if a [resource](resources) interface not to a concrete resource), +and optionals. + +```cadence +// Declare a constant named `values` which has type `[AnyStruct]`, +// i.e. an array of arbitrarily typed values. +// +let values: [AnyStruct] = [1, true] + +let first = values[0] as? Int +// `first` is `1` and has type `Int?` + +let second = values[1] as? Bool +// `second` is `true` and has type `Bool?` +``` + +### Force-downcasting Operator + +The force-downcasting operator `as!` behaves like the +[conditional downcasting operator `as?`](#conditional-downcasting-operator). +However, if the cast succeeds, it returns a value of the given type instead of an optional, +and if the cast fails, it aborts the program instead of returning `nil`, + +```cadence +// Declare a constant named `something` which has type `AnyStruct`, +// with an initial value which has type `Int`. +// +let something: AnyStruct = 1 + +// Force-downcast the value of `something` to `Int`. +// The cast succeeds, because the value has type `Int`. +// +let number = something as! Int +// `number` is `1` and has type `Int` + +// Force-downcast the value of `something` to `Bool`. +// The cast fails, because the value has type `Int`, +// and `Bool` is not a subtype of `Int`. +// +let boolean = something as! Bool +// Run-time error +``` + ## Precedence and Associativity Operators have the following precedences, highest to lowest: diff --git a/docs/language/values-and-types.mdx b/docs/language/values-and-types.mdx index 009219336f..bf8e94fb9d 100644 --- a/docs/language/values-and-types.mdx +++ b/docs/language/values-and-types.mdx @@ -446,7 +446,7 @@ let maybeInt: Int? = 1 let anything: AnyStruct = maybeInt ``` -[Conditional downcasting](#conditional-downcasting-operator) allows coercing +[Conditional downcasting](operators#conditional-downcasting-operator) allows coercing a value which has the type `AnyStruct` or `AnyResource` back to its original type. ## Optionals @@ -644,54 +644,6 @@ The force-assignment operator is only used for [resource types](resources) and the move operator (`<-`), which are covered in the resources section of this document. -### Conditional Downcasting Operator - -The conditional downcasting operator `as?` can be used to type cast a value to a type. -The operator returns an optional. -If the value has a type that is a subtype of the given type that should be casted to, -the operator returns the value as the given type, -otherwise the result is `nil`. - -The cast and check is performed at run-time, i.e. when the program is executed, -not statically, i.e. when the program is checked. - -```cadence -// Declare a constant named `something` which has type `AnyStruct`, -// with an initial value which has type `Int`. -// -let something: AnyStruct = 1 - -// Conditionally downcast the value of `something` to `Int`. -// The cast succeeds, because the value has type `Int`. -// -let number = something as? Int -// `number` is `1` and has type `Int?` - -// Conditionally downcast the value of `something` to `Bool`. -// The cast fails, because the value has type `Int`, -// and `Bool` is not a subtype of `Int`. -// -let boolean = something as? Bool -// `boolean` is `nil` and has type `Bool?` -``` - -Downcasting works for nested types (e.g. arrays), -interfaces (if a [resource](resources) interface not to a concrete resource), -and optionals. - -```cadence -// Declare a constant named `values` which has type `[AnyStruct]`, -// i.e. an array of arbitrarily typed values. -// -let values: [AnyStruct] = [1, true] - -let first = values[0] as? Int -// `first` is `1` and has type `Int?` - -let second = values[1] as? Bool -// `second` is `true` and has type `Bool?` -``` - ## Never `Never` is the bottom type, i.e., it is a subtype of all types. From 2687f51ec6e628f4bdab393c7d57747d721052a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:44:20 -0700 Subject: [PATCH 02/11] update core events documentation --- docs/language/accounts.mdx | 21 ++++----- docs/language/core-events.md | 85 ++++++++++++++++++++++-------------- 2 files changed, 64 insertions(+), 42 deletions(-) diff --git a/docs/language/accounts.mdx b/docs/language/accounts.mdx index 59a067d727..694a1ac0bd 100644 --- a/docs/language/accounts.mdx +++ b/docs/language/accounts.mdx @@ -163,10 +163,10 @@ to the `prepare` phase of the transaction. fun getAuthAccount(_ address: Address): AuthAccount ``` - This `AuthAccount` object can perform all operations associated with authorized accounts, - and as such this function is only available in scripts, - which discard their changes upon completion. - Attempting to use this function outside of a script will cause a type error. + This `AuthAccount` object can perform all operations associated with authorized accounts, + and as such this function is only available in scripts, + which discard their changes upon completion. + Attempting to use this function outside of a script will cause a type error. ## Account Creation @@ -198,7 +198,8 @@ struct AccountKey { let isRevoked: Bool } ``` -Refer the [PublicKey](crypto/#publickey) section for more details on the creation and validity of public keys. + +Refer the [`PublicKey` section](crypto/#publickey) for more details on the creation and validity of public keys. ### Account Key API Account key API provides a set of functions to manage account keys. @@ -393,7 +394,7 @@ to all its stored objects. Reads the type of an object from the account's storage which is stored under the given path, or nil if no object is stored under the given path. - If there is an object stored, the type of the object is returned without modifying the stored object. + If there is an object stored, the type of the object is returned without modifying the stored object. The path must be a storage path, i.e., only the domain `storage` is allowed @@ -410,7 +411,7 @@ to all its stored objects. A type argument for the parameter must be provided explicitly. The type `T` must be a supertype of the type of the loaded object. - If it is not, execution will abort with an error. + If it is not, execution will abort with an error. The given type does not necessarily need to be exactly the same as the type of the loaded object. The path must be a storage path, i.e., only the domain `storage` is allowed. @@ -427,7 +428,7 @@ to all its stored objects. A type argument for the parameter must be provided explicitly. The type `T` must be a supertype of the type of the copied structure. - If it is not, execution will abort with an error. + If it is not, execution will abort with an error. The given type does not necessarily need to be exactly the same as the type of the copied structure. @@ -532,7 +533,7 @@ This is possible using the `borrow` function of an `AuthAccount`: A type argument for the parameter must be provided explicitly. The type argument must be a reference to any type (`&Any`; `Any` is the supertype of all types). It must be possible to create the given reference type `T` for the stored / borrowed object. - If it is not, execution will abort with an error. + If it is not, execution will abort with an error. The given type does not necessarily need to be exactly the same as the type of the borrowed object. The path must be a storage path, i.e., only the domain `storage` is allowed. @@ -609,7 +610,7 @@ An account's storage is limited by its storage capacity. An account's storage used is the sum of the size of all the data that is stored in an account (in MB). An account's storage capacity is a value that is calculated from the amount of FLOW -that is stored in the account's main FLOW token vault. +that is stored in the account's main FLOW token vault. At the end of every transaction, the storage used is compared to the storage capacity. For all accounts involved in the transaction, if the account's storage used is greater than its storage capacity, the transaction will fail. diff --git a/docs/language/core-events.md b/docs/language/core-events.md index 62b868beed..becb4f5921 100644 --- a/docs/language/core-events.md +++ b/docs/language/core-events.md @@ -2,7 +2,10 @@ title: Core Events --- -Core events are events emitted directly from the FVM (Flow virtual machine). The events have the same name on all networks and don't follow the standard naming. +Core events are events emitted directly from the FVM (Flow virtual machine). +The events have the same name on all networks and do not follow the standard naming (they have no address). + +Refer the [`PublicKey` section](crypto/#publickey) for more details on the information provided for account key events. ### Account Created @@ -15,9 +18,9 @@ Event name: `flow.AccountCreated` pub event AccountCreated(address: Address) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the newly created account | +| Field | Type | Description | +| ----------------- | --------- | ---------------------------------------- | +| `address` | `Address` | The address of the newly created account | ### Account Key Added @@ -27,13 +30,16 @@ Event that is emitted when a key gets added to an account. Event name: `flow.AccountKeyAdded` ```cadence -pub event AccountKeyAdded(address: Address, publicKey: [UInt8]) +pub event AccountKeyAdded( + address: Address, + publicKey: PublicKey +) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the account the key is added to | -| publicKey | [UInt8] | Public key added to an account | +| Field | Type | Description | +| ------------- | ----------- | ----------------------------------------------- | +| `address` | `Address` | The address of the account the key is added to | +| `publicKey` | `PublicKey` | The public key added to the account | ### Account Key Removed @@ -43,13 +49,16 @@ Event that is emitted when a key gets removed from an account. Event name: `flow.AccountKeyRemoved` ```cadence -pub event AccountKeyRemoved(address: Address, publicKey: [UInt8]) +pub event AccountKeyRemoved( + address: Address, + publicKey: PublicKey +) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the account the key is removed from | -| publicKey | [UInt8] | Public key removed from an account | +| Field | Type | Description | +| ----------- | ----------- | --------------------------------------------------- | +| `address` | `Address` | The address of the account the key is removed from | +| `publicKey` | `PublicKey` | Public key removed from the account | ### Account Contract Added @@ -59,14 +68,18 @@ Event that is emitted when a contract gets deployed to an account. Event name: `flow.AccountContractAdded` ```cadence -pub event AccountContractAdded(address: Address, codeHash: [UInt8], contract: String) +pub event AccountContractAdded( + address: Address, + codeHash: [UInt8], + contract: String +) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the account the contract gets deployed to | -| codeHash | [UInt8] | Hash of the contract source code | -| contract | String | The name of the the contract | +| Field | Type | Description | +| ----------- | ------ | ------------------------------------------------------------ | +| `address` | `Address` | The address of the account the contract gets deployed to | +| `codeHash` | `[UInt8]` | Hash of the contract source code | +| `contract` | `String` | The name of the the contract | ### Account Contract Updated @@ -75,14 +88,18 @@ Event that is emitted when a contract gets updated on an account. Event name: `flow.AccountContractUpdated` ```cadence -pub event AccountContractUpdated(address: Address, codeHash: [UInt8], contract: String) +pub event AccountContractUpdated( + address: Address, + codeHash: [UInt8], + contract: String +) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the account the contract gets updated on | -| codeHash | [UInt8] | Hash of the contract source code | -| contract | String | The name of the the contract | +| Field | Type | Description | +| ----------- | --------- | -------------------------------------------------------- | +| `address` | `Address` | The address of the account the contract gets updated on | +| `codeHash` | `[UInt8]` | Hash of the contract source code | +| `contract` | `String` | The name of the the contract | ### Account Contract Removed @@ -92,12 +109,16 @@ Event that is emitted when a contract gets removed from an account. Event name: `flow.AccountContractRemoved` ```cadence -pub event AccountContractRemoved(address: Address, codeHash: [UInt8], contract: String) +pub event AccountContractRemoved( + address: Address, + codeHash: [UInt8], + contract: String +) ``` -| Field | Type | Description | -| ----------------- | ------ | ---------------------------------------------------------------------- | -| address | Address | The address of the account the contract gets removed from | -| codeHash | [UInt8] | Hash of the contract source code | -| contract | String | The name of the the contract | +| Field | Type | Description | +| ----------- | --------- | --------------------------------------------------------- | +| `address` | `Address` | The address of the account the contract gets removed from | +| `codeHash` | `[UInt8]` | Hash of the contract source code | +| `contract` | `String` | The name of the the contract | From d3191a3529c8faf33dc3dbb4a335569ae70c784d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:48:08 -0700 Subject: [PATCH 03/11] remove unimplemented features and describe current behaviour --- docs/language/built-in-functions.mdx | 11 +- docs/language/composite-types.mdx | 277 +-------------------------- docs/language/functions.mdx | 64 +++---- docs/language/interfaces.mdx | 250 +----------------------- 4 files changed, 41 insertions(+), 561 deletions(-) diff --git a/docs/language/built-in-functions.mdx b/docs/language/built-in-functions.mdx index 98d19c769d..d18a4e5b60 100644 --- a/docs/language/built-in-functions.mdx +++ b/docs/language/built-in-functions.mdx @@ -14,6 +14,7 @@ title: Built-in Functions ``` ## assert + `cadence•fun assert(_ condition: Bool, message: String)` Terminates the program if the given condition is false, @@ -23,6 +24,7 @@ title: Built-in Functions The message argument is optional. ## unsafeRandom + `cadence•fun unsafeRandom(): UInt64` Returns a pseudo-random number. @@ -34,20 +36,13 @@ title: Built-in Functions ## RLP - - -🚧 Status: This API is going to be available in an upcoming release of Cadence - - - - RLP (Recursive Length Prefix) serialization allows the encoding of arbitrarily nested arrays of binary data. Cadence provides RLP decoding functions in the built-in `RLP` contract, which does not need to be imported. - `cadence•fun decodeString(_ input: [UInt8]): [UInt8]` - Decodes an RLP-encoded byte array (called string in the context of RLP). + Decodes an RLP-encoded byte array (called string in the context of RLP). The byte array should only contain of a single encoded value for a string; if the encoded value type does not match, or it has trailing unnecessary bytes, the program aborts. If any error is encountered while decoding, the program aborts. diff --git a/docs/language/composite-types.mdx b/docs/language/composite-types.mdx index e1fb5c521a..542651208c 100644 --- a/docs/language/composite-types.mdx +++ b/docs/language/composite-types.mdx @@ -129,22 +129,10 @@ There are three kinds of fields: Variable fields are declared using the `var` keyword. -- **Synthetic fields** are **not stored** in the composite value, - i.e. they are derived/computed from other values. - They can have new values assigned to them. - - Synthetic fields are declared using the `synthetic` keyword. - - Synthetic fields must have a getter and a setter. - Getters and setters are explained in the - [next section](#composite-type-field-getters-and-setters). - Synthetic fields are explained in a [separate section](#synthetic-composite-type-fields). - -| Field Kind | Stored in memory | Assignable | Keyword | -|----------------------|------------------|--------------------|-------------| -| **Variable field** | Yes | Yes | `var` | -| **Constant field** | Yes | **No** | `let` | -| **Synthetic field** | **No** | Yes | `synthetic` | +| Field Kind | Assignable | Keyword | +|----------------------|--------------------|-------------| +| **Variable field** | Yes | `var` | +| **Constant field** | **No** | `let` | In initializers, the special constant `self` refers to the composite value that is to be initialized. @@ -238,229 +226,10 @@ token.balance = 1 token.id = 23 ``` -## Composite Data Initializer Overloading - - - -🚧 Status: Initializer overloading is not implemented yet. - - - -Initializers support overloading. -This allows for example providing default values for certain parameters. - -```cadence -// Declare a structure named `Token`, which has a constant field -// named `id` and a variable field named `balance`. -// -// The first initializer allows initializing both fields with a given value. -// -// A second initializer is provided for convenience to initialize the `id` field -// with a given value, and the `balance` field with the default value `0`. -// -pub struct Token { - let id: Int - var balance: Int - - init(id: Int, balance: Int) { - self.id = id - self.balance = balance - } - - init(id: Int) { - self.id = id - self.balance = 0 - } -} -``` - -## Composite Type Field Getters and Setters - - - -🚧 Status: Field getters and setters are not implemented yet. - - - -Fields may have an optional getter and an optional setter. -Getters are functions that are called when a field is read, -and setters are functions that are called when a field is written. -Only certain assignments are allowed in getters and setters. - -Getters and setters are enclosed in opening and closing braces, after the field's type. - -Getters are declared using the `get` keyword. -Getters have no parameters and their return type is implicitly the type of the field. - -```cadence -pub struct GetterExample { - - // Declare a variable field named `balance` with a getter - // which ensures the read value is always non-negative. - // - pub var balance: Int { - get { - if self.balance < 0 { - return 0 - } - - return self.balance - } - } - - init(balance: Int) { - self.balance = balance - } -} - -let example = GetterExample(balance: 10) -// `example.balance` is `10` - -example.balance = -50 -// The stored value of the field `example` is `-50` internally, -// though `example.balance` is `0` because the getter for `balance` returns `0` instead. -``` - -Setters are declared using the `set` keyword, -followed by the name for the new value enclosed in parentheses. -The parameter has implicitly the type of the field. -Another type cannot be specified. Setters have no return type. - -The types of values assigned to setters must always match the field's type. - -```cadence -pub struct SetterExample { - - // Declare a variable field named `balance` with a setter - // which requires written values to be positive. - // - pub var balance: Int { - set(newBalance) { - pre { - newBalance >= 0 - } - self.balance = newBalance - } - } - - init(balance: Int) { - self.balance = balance - } -} - -let example = SetterExample(balance: 10) -// `example.balance` is `10` - -// Run-time error: The precondition of the setter for the field `balance` fails, -// the program aborts. -// -example.balance = -50 -``` - -## Synthetic Composite Type Fields - - - -🚧 Status: Synthetic fields are not implemented yet. - - - -Fields which are not stored in the composite value are *synthetic*, -i.e., the field value is computed. -Synthetic can be either read-only, or readable and writable. - -Synthetic fields are declared using the `synthetic` keyword. - -Synthetic fields are read-only when only a getter is provided. - -```cadence -struct Rectangle { - pub var width: Int - pub var height: Int - - // Declare a synthetic field named `area`, - // which computes the area based on the `width` and `height` fields. - // - pub synthetic area: Int { - get { - return width * height - } - } - - // Declare an initializer which accepts width and height. - // As `area` is synthetic and there is only a getter provided for it, - // the `area` field cannot be assigned a value. - // - init(width: Int, height: Int) { - self.width = width - self.height = height - } -} -``` - -Synthetic fields are readable and writable when both a getter and a setter is declared. - -```cadence -// Declare a struct named `GoalTracker` which stores a number -// of target goals, a number of completed goals, -// and has a synthetic field to provide the left number of goals. -// -// NOTE: the tracker only implements some functionality to demonstrate -// synthetic fields, it is incomplete (e.g. assignments to `goal` are not handled properly). -// -pub struct GoalTracker { - - pub var goal: Int - pub var completed: Int - - // Declare a synthetic field which is both readable and writable. - // - // When the field is read from (in the getter), the number - // of left goals is computed from the target number of goals - // and the completed number of goals. - // - // When the field is written to (in the setter), the number - // of completed goals is updated, based on the number - // of target goals and the new remaining number of goals. - // - pub synthetic left: Int { - get { - return self.goal - self.completed - } - - set(newLeft) { - self.completed = self.goal - newLeft - } - } - - init(goal: Int, completed: Int) { - self.goal = goal - self.completed = completed - } -} - -let tracker = GoalTracker(goal: 10, completed: 0) -// `tracker.goal` is `10` -// `tracker.completed` is `0` -// `tracker.left` is `10` - -tracker.completed = 1 -// `tracker.left` is `9` - -tracker.left = 8 -// `tracker.completed` is `2` -``` - -It is invalid to declare a synthetic field with only a setter. +Initializers do not support overloading. ## Composite Type Functions - - -🚧 Status: Function overloading is not implemented yet. - - - Composite types may contain functions. Just like in the initializer, the special constant `self` refers to the composite value that the function is called on. @@ -493,41 +262,7 @@ rectangle.scale(factor: 4) // `rectangle.height` is `12` ``` -Functions support overloading. - -```cadence -// Declare a structure named "Rectangle", which represents a rectangle -// and has variable fields for the width and height. -// -pub struct Rectangle { - pub var width: Int - pub var height: Int - - init(width: Int, height: Int) { - self.width = width - self.height = height - } - - // Declare a function named "scale", which independently scales - // the width by a given factor and the height by a given factor. - // - pub fun scale(widthFactor: Int, heightFactor: Int) { - self.width = self.width * widthFactor - self.height = self.height * heightFactor - } - - // Declare another function also named "scale", which scales - // both width and height by a given factor. - // The function calls the `scale` function declared above. - // - pub fun scale(factor: Int) { - self.scale( - widthFactor: factor, - heightFactor: factor - ) - } -} -``` + Functions do not support overloading. ## Composite Type Subtyping diff --git a/docs/language/functions.mdx b/docs/language/functions.mdx index 0583a924b7..9a4bfbac8f 100644 --- a/docs/language/functions.mdx +++ b/docs/language/functions.mdx @@ -202,33 +202,7 @@ fun doubleAndAddOne(_ x: Int): Int { doubleAndAddOne(2) // is `5` ``` -## Function Overloading - - - -🚧 Status: Function overloading is not implemented. - - - -It is possible to declare functions with the same name, -as long as they have different sets of argument labels. -This is known as function overloading. - -```cadence -// Declare a function named "assert" which requires a test value -// and a message argument. -// -fun assert(_ test: Bool, message: String) { - // ... -} - -// Declare a function named "assert" which only requires a test value. -// The function calls the `assert` function declared above. -// -fun assert(_ test: Bool) { - assert(test, message: "test is false") -} -``` +Functions do not support overloading. ## Function Expressions @@ -446,17 +420,6 @@ Postconditions may only occur after preconditions, if any. A conditions block consists of one or more conditions. Conditions are expressions evaluating to a boolean. -They may not call functions, i.e., they cannot have side-effects and must be pure expressions. -Also, conditions may not contain function expressions. - - Conditions may be written on separate lines, or multiple conditions can be written on the same line, @@ -516,3 +479,28 @@ fun incrementN() { } ``` +## Functions are Values + +Functions are values ("first class"), so e.g. may be assigned to variables and fields, +or passed to functions as arguments. + + +```cadence +// Declare a function named `transform` which applies a function to each element +// of an array of integers and returns a new array of the results. +// +pub fun transform(function: ((Int): Int), integers: [Int]): [Int] { + var newIntegers: [Int] = [] + for integer in integers { + newIntegers.append(function(integer)) + } + return newIntegers +} + +pub fun double(_ integer: Int): Int { + return integer * 2 +} + +let newIntegers = transform(function: double, integers: [1, 2, 3]) +// `newIntegers` is `[2, 4, 6]` +``` diff --git a/docs/language/interfaces.mdx b/docs/language/interfaces.mdx index dfc2747af7..980cb230cd 100644 --- a/docs/language/interfaces.mdx +++ b/docs/language/interfaces.mdx @@ -56,8 +56,7 @@ Field requirements can be annotated to require the implementation to be a variable field, by using the `var` keyword; require the implementation to be a constant field, by using the `let` keyword; or the field requirement may specify nothing, -in which case the implementation may either be -a variable field, a constant field, or a synthetic field. +in which case the implementation may either be a variable or a constant field. Field requirements and function requirements must specify the required level of access. The access must be at least be public, so the `pub` keyword must be provided. @@ -78,22 +77,10 @@ pub resource interface FungibleToken { // that is readable in all scopes (`pub`). // // Neither the `var` keyword, nor the `let` keyword is used, - // so the field may be implemented as either a variable field, - // a constant field, or a synthetic field. + // so the field may be implemented as either a variable + // or as a constant field. // - // The read balance must always be positive. - // - // NOTE: no requirement is made for the kind of field, - // it can be either variable or constant in the implementation. - // - pub balance: Int { - set(newBalance) { - pre { - newBalance >= 0: - "Balances are always set as non-negative numbers" - } - } - } + pub balance: Int // Require the implementing type to provide an initializer that // given the initial balance, must initialize the balance field. @@ -306,8 +293,8 @@ but also publicly settable (the `pub(set)` keyword is specified). ```cadence pub struct interface AnInterface { // Require the implementing type to provide a publicly readable - // field named `a` that has type `Int`. It may be a constant field, - // a variable field, or a synthetic field. + // field named `a` that has type `Int`. It may be a variable + // or a constant field. // pub a: Int } @@ -442,37 +429,6 @@ shape.scale(factor: 3) shape.area // is `54` ``` -## Interface Implementation Requirements - - - -🚧 Status: Interface implementation requirements is not implemented yet. - - - -Interfaces can require implementing types -to also implement other interfaces of the same kind. -Interface implementation requirements can be declared -by following the interface name with a colon (`:`) -and one or more names of interfaces of the same kind, separated by commas. - -```cadence -// Declare a structure interface named `Shape`. -// -pub struct interface Shape {} - -// Declare a structure interface named `Polygon`. -// Require implementing types to also implement the structure interface `Shape`. -// -pub struct interface Polygon: Shape {} - -// Declare a structure named `Hexagon` that implements the `Polygon` interface. -// This also is required to implement the `Shape` interface, -// because the `Polygon` interface requires it. -// -pub struct Hexagon: Polygon {} -``` - ## Interface Nesting @@ -511,197 +467,3 @@ resource SomeOuter: OuterInterface {} struct SomeInner: OuterInterface.InnerInterface {} ``` - -## Nested Type Requirements - - - -🚧 Status: Currently only contracts and contract interfaces support nested type requirements. - - - -Interfaces can require implementing types to provide concrete nested types. -For example, a resource interface may require an implementing type to provide a resource type. - -```cadence -// Declare a resource interface named `FungibleToken`. -// -// Require implementing types to provide a resource type named `Vault` -// which must have a field named `balance`. -// -resource interface FungibleToken { - - pub resource Vault { - pub balance: Int - } -} - -// Declare a resource named `ExampleToken` that implements the `FungibleToken` interface. -// -// The nested type `Vault` must be provided to conform to the interface. -// -resource ExampleToken: FungibleToken { - - pub resource Vault { - pub var balance: Int - - init(balance: Int) { - self.balance = balance - } - } -} -``` - -## `Equatable` Interface - - - -🚧 Status: The `Equatable` interface is not implemented yet. - - - -An equatable type is a type that can be compared for equality. -Types are equatable when they implement the `Equatable` interface. - -Equatable types can be compared for equality using the equals operator (`==`) -or inequality using the unequals operator (`!=`). - -Most of the built-in types are equatable, like booleans and integers. -Arrays are equatable when their elements are equatable. -Dictionaries are equatable when their values are equatable. - -To make a type equatable the `Equatable` interface must be implemented, -which requires the implementation of the function `equals`, -which accepts another value that the given value should be compared for equality. - -```cadence -struct interface Equatable { - pub fun equals(_ other: {Equatable}): Bool -} -``` - -```cadence -// Declare a struct named `Cat`, which has one field named `id` -// that has type `Int`, i.e., the identifier of the cat. -// -// `Cat` also will implement the interface `Equatable` -// to allow cats to be compared for equality. -// -struct Cat: Equatable { - pub let id: Int - - init(id: Int) { - self.id = id - } - - pub fun equals(_ other: {Equatable}): Bool { - if let otherCat = other as? Cat { - // Cats are equal if their identifier matches. - // - return otherCat.id == self.id - } else { - return false - } - } -} - -Cat(1) == Cat(2) // is `false` -Cat(3) == Cat(3) // is `true` -``` - -## `Hashable` Interface - - - -🚧 Status: The `Hashable` interface is not implemented yet. - - - -A hashable type is a type that can be hashed to an integer hash value, -i.e., it is distilled into a value that is used as evidence of inequality. -Types are hashable when they implement the `Hashable` interface. - -Hashable types can be used as keys in dictionaries. - -Hashable types must also be equatable, -i.e., they must also implement the `Equatable` interface. -This is because the hash value is only evidence for inequality: -two values that have different hash values are guaranteed to be unequal. -However, if the hash values of two values are the same, -then the two values could still be unequal -and just happen to hash to the same hash value. -In that case equality still needs to be determined through an equality check. -Without `Equatable`, values could be added to a dictionary, -but it would not be possible to retrieve them. - -Most of the built-in types are hashable, like booleans and integers. -Arrays are hashable when their elements are hashable. -Dictionaries are hashable when their values are equatable. - -Hashing a value means passing its essential components into a hash function. -Essential components are those that are used in the type's implementation of `Equatable`. - -If two values are equal because their `equals` function returns true, -then the implementation must return the same integer hash value for each of the two values. - -The implementation must also consistently return the same integer hash value during the execution -of the program when the essential components have not changed. -The integer hash value need not necessarily be the same across multiple executions. - -```cadence -struct interface Hashable: Equatable { - pub hashValue: Int -} -``` - -```cadence -// Declare a structure named `Point` with two fields -// named `x` and `y` that have type `Int`. -// -// `Point` is declared to implement the `Hashable` interface, -// which also means it needs to implement the `Equatable` interface. -// -struct Point: Hashable { - - pub(set) var x: Int - pub(set) var y: Int - - init(x: Int, y: Int) { - self.x = x - self.y = y - } - - // Implementing the function `equals` will allow points to be compared - // for equality and satisfies the `Equatable` interface. - // - pub fun equals(_ other: {Equatable}): Bool { - if let otherPoint = other as? Point { - // Points are equal if their coordinates match. - // - // The essential components are therefore the fields `x` and `y`, - // which must be used in the implementation of the field requirement - // `hashValue` of the `Hashable` interface. - // - return otherPoint.x == self.x - && otherPoint.y == self.y - } else { - return false - } - } - - // Providing an implementation for the hash value field - // satisfies the `Hashable` interface. - // - pub synthetic hashValue: Int { - get { - // Calculate a hash value based on the essential components, - // the fields `x` and `y`. - // - var hash = 7 - hash = 31 * hash + self.x - hash = 31 * hash + self.y - return hash - } - } -} -``` From 241952d3fd713173d6639b05446a87ee38d35e2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:48:22 -0700 Subject: [PATCH 04/11] use proper symbols --- docs/language/values-and-types.mdx | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/docs/language/values-and-types.mdx b/docs/language/values-and-types.mdx index bf8e94fb9d..af7164debf 100644 --- a/docs/language/values-and-types.mdx +++ b/docs/language/values-and-types.mdx @@ -73,12 +73,12 @@ or _unsigned_ (positive or zero). Signed integer types which check for overflow and underflow have an `Int` prefix and can represent values in the following ranges: -- **`Int8`**: −2^7 through 2^7 − 1 (-128 through 127) -- **`Int16`**: −2^15 through 2^15 − 1 (-32768 through 32767) -- **`Int32`**: −2^31 through 2^31 − 1 (-2147483648 through 2147483647) -- **`Int64`**: −2^63 through 2^63 − 1 (-9223372036854775808 through 9223372036854775807) -- **`Int128`**: −2^127 through 2^127 − 1 -- **`Int256`**: −2^255 through 2^255 − 1 +- **`Int8`**: -2^7 through 2^7 − 1 (-128 through 127) +- **`Int16`**: -2^15 through 2^15 − 1 (-32768 through 32767) +- **`Int32`**: -2^31 through 2^31 − 1 (-2147483648 through 2147483647) +- **`Int64`**: -2^63 through 2^63 − 1 (-9223372036854775808 through 9223372036854775807) +- **`Int128`**: -2^127 through 2^127 − 1 +- **`Int256`**: -2^255 through 2^255 − 1 Unsigned integer types which check for overflow and underflow have a `UInt` prefix and can represent values in the following ranges: From 4364e19fdf1f828946e304a8f29607f72caa0e08 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:48:40 -0700 Subject: [PATCH 05/11] document bitwise operators --- docs/language/operators.md | 59 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/docs/language/operators.md b/docs/language/operators.md index 0b47bbec6c..8ac441b06f 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -420,6 +420,65 @@ Values of these types need to be cast to the desired type before performing the let z: Bool = (x as! Int8) > (y as! Int8) ``` +## Bitwise Operators + +Bitwise operators enable the manipulation of individual bits of integers. +They're often used in low-level programming. + +- Bitwise AND: `a & b` + + Returns a new integer whose bits are 1 only if the bits were 1 in *both* input integers: + + ```cadence + let firstFiveBits = 0b11111000 + let lastFiveBits = 0b00011111 + let middleTwoBits = firstFiveBits & lastFiveBits // is 0b00011000 + ``` + +- Bitwise OR: `a | b` + + Returns a new integer whose bits are 1 only if the bits were 1 in *either* input integers: + + ```cadence + let someBits = 0b10110010 + let moreBits = 0b01011110 + let combinedbits = someBits | moreBits // is 0b11111110 + ``` + +- Bitwise XOR: `a ^ b` + + Returns a new integer whose bits are set to 1 where the input bits are different, + and are set to 0 where the input bits are the same: + + ```cadence + let firstBits = 0b00010100 + let otherBits = 0b00000101 + let outputBits = firstBits ^ otherBits // is 0b00010001 + ``` + +### Bitwise Shifting Operators + +- Bitwise LEFT SHIFT: `a << b` + + Returns a new integer with all bits moved to the left by a certain number of places. + + ```cadence + let someBits = 4 // is 0b00000100 + let shiftedBits = someBits << 2 // is 0b00010000 + ``` + +- Bitwise RIGHT SHIFT: `a >> b` + + Returns a new integer with all bits moved to the right by a certain number of places. + + ```cadence + let someBits = 8 // is 0b00001000 + let shiftedBits = someBits >> 2 // is 0b00000010 + ``` + +For unsigned integersm, the bitwise shifting operators perform [logical shifting](https://en.wikipedia.org/wiki/Logical_shift), +for signed integers, they perform [arithmetic shifting](https://en.wikipedia.org/wiki/Arithmetic_shift). + ## Ternary Conditional Operator There is only one ternary conditional operator, the ternary conditional operator (`a ? b : c`). From 724c0d5fbe5930d0c4a8ff88f8ddd77903ad6b85 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:48:57 -0700 Subject: [PATCH 06/11] clean up operators documentation --- docs/language/operators.md | 58 ++++++++++++++++++++------------------ 1 file changed, 30 insertions(+), 28 deletions(-) diff --git a/docs/language/operators.md b/docs/language/operators.md index 8ac441b06f..b0be9d57a4 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -16,23 +16,7 @@ They are either unary, binary, or ternary. The first operator symbol appears between the first and second value, the second operator symbol appears between the second and third value (infix). -## Negation - -The `-` unary operator negates an integer: - -```cadence -let a = 1 --a // is `-1` -``` - -The `!` unary operator logically negates a boolean: - -```cadence -let a = true -!a // is `false` -``` - -## Assignment +## Assignment Operator The binary assignment operator `=` can be used to assign a new value to a variable. @@ -103,7 +87,7 @@ dictionaries[false][3] = 0 //}` ``` -## Swapping +## Swapping Operator The binary swap operator `<->` can be used to exchange the values of two variables. @@ -140,9 +124,16 @@ a <-> b Both sides of the swap operation must be an identifier, followed by one or more index or access expressions. -## Arithmetic +## Arithmetic Operators + +The unary pefix operator `-` negates an integer: -There are four arithmetic operators: +```cadence +let a = 1 +-a // is `-1` +``` + +There are four binary arithmetic operators: - Addition: `+` - Subtraction: `-` @@ -226,10 +217,11 @@ let b: Word8 = 0 b - 1 // is `255` ``` -#### Arithmetics on number super-types -Arithmetic operators are not supported for number supertypes (`Number`, `SignedNumber` -`FixedPoint`, `SignedFixedPoint`, `Integer`, `SignedInteger`), as they may or may not -succeed at run-time. +### Arithmetics on number super-types + +Arithmetic operators are not supported for number supertypes +(`Number`, `SignedNumber`, `FixedPoint`, `SignedFixedPoint`, `Integer`, `SignedInteger`), +as they may or may not succeed at run-time. ```cadence let x: Integer = 3 as Int8 @@ -248,6 +240,15 @@ let z: Integer = (x as! Int8) + (y as! Int8) Logical operators work with the boolean values `true` and `false`. +- Logical NOT: `!a` + + This unary prefix operator logically negates a boolean: + + ```cadence + let a = true + !a // is `false` + ``` + - Logical AND: `a && b` ```cadence @@ -276,7 +277,7 @@ Logical operators work with the boolean values `true` and `false`. If the left-hand side is true, the right-hand side is not evaluated. -## Comparison operators +## Comparison Operators Comparison operators work with boolean and integer values. @@ -402,10 +403,11 @@ Comparison operators work with boolean and integer values. 2 >= 1 // is `true` ``` -#### Comparing number super-types +### Comparing number super-types + Similar to arithmetic operators, comparison operators are also not supported for number supertypes -(`Number`, `SignedNumber` `FixedPoint`, `SignedFixedPoint`, `Integer`, `SignedInteger`), as they -may or may not succeed at run-time. +(`Number`, `SignedNumber` `FixedPoint`, `SignedFixedPoint`, `Integer`, `SignedInteger`), +as they may or may not succeed at run-time. ```cadence let x: Integer = 3 as Int8 From d47532c8f205fe901a37c084cb431965a69cacb2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Sat, 25 Jun 2022 15:49:14 -0700 Subject: [PATCH 07/11] fix code example and add explanation comment --- docs/language/resources.mdx | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/docs/language/resources.mdx b/docs/language/resources.mdx index 9aaa283d64..4536d917d0 100644 --- a/docs/language/resources.mdx +++ b/docs/language/resources.mdx @@ -439,7 +439,12 @@ resources["r1"] <- create R() // in a resource dictionary, use a swap statement with a variable to replace // the accessed element. // -var res <- create R() +// The result of a dictionary read is optional, as the given key might not +// exist in the dictionary. +// The types on both sides of the swap operator must be the same, +// so also declare the variable as an optional. +// +var res: @R? <- create R() resources["r1"] <-> res // `resources["r1"]` now contains the new resource. // `res` now contains the old resource. From 2c612581292e902550c63b0acca9cae7d02baf54 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 27 Jun 2022 09:50:23 -0700 Subject: [PATCH 08/11] Apply suggestions from code review Co-authored-by: Daniel Sainati --- docs/language/accounts.mdx | 2 +- docs/language/core-events.md | 4 ++-- docs/language/functions.mdx | 2 +- docs/language/operators.md | 16 +++++++--------- 4 files changed, 11 insertions(+), 13 deletions(-) diff --git a/docs/language/accounts.mdx b/docs/language/accounts.mdx index 694a1ac0bd..e807a5d87f 100644 --- a/docs/language/accounts.mdx +++ b/docs/language/accounts.mdx @@ -199,7 +199,7 @@ struct AccountKey { } ``` -Refer the [`PublicKey` section](crypto/#publickey) for more details on the creation and validity of public keys. +Refer to the [`PublicKey` section](crypto/#publickey) for more details on the creation and validity of public keys. ### Account Key API Account key API provides a set of functions to manage account keys. diff --git a/docs/language/core-events.md b/docs/language/core-events.md index becb4f5921..4668c5cd05 100644 --- a/docs/language/core-events.md +++ b/docs/language/core-events.md @@ -2,10 +2,10 @@ title: Core Events --- -Core events are events emitted directly from the FVM (Flow virtual machine). +Core events are events emitted directly from the FVM (Flow Virtual Machine). The events have the same name on all networks and do not follow the standard naming (they have no address). -Refer the [`PublicKey` section](crypto/#publickey) for more details on the information provided for account key events. +Refer to the [`PublicKey` section](crypto/#publickey) for more details on the information provided for account key events. ### Account Created diff --git a/docs/language/functions.mdx b/docs/language/functions.mdx index 9a4bfbac8f..4af0de34c7 100644 --- a/docs/language/functions.mdx +++ b/docs/language/functions.mdx @@ -481,7 +481,7 @@ fun incrementN() { ## Functions are Values -Functions are values ("first class"), so e.g. may be assigned to variables and fields, +Functions are values ("first-class"), so they may be assigned to variables and fields or passed to functions as arguments. diff --git a/docs/language/operators.md b/docs/language/operators.md index b0be9d57a4..1974e3cbf0 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -449,8 +449,8 @@ They're often used in low-level programming. - Bitwise XOR: `a ^ b` - Returns a new integer whose bits are set to 1 where the input bits are different, - and are set to 0 where the input bits are the same: + Returns a new integer whose bits are 1 where the input bits are different, + and are 0 where the input bits are the same: ```cadence let firstBits = 0b00010100 @@ -478,7 +478,7 @@ They're often used in low-level programming. let shiftedBits = someBits >> 2 // is 0b00000010 ``` -For unsigned integersm, the bitwise shifting operators perform [logical shifting](https://en.wikipedia.org/wiki/Logical_shift), +For unsigned integers, the bitwise shifting operators perform [logical shifting](https://en.wikipedia.org/wiki/Logical_shift), for signed integers, they perform [arithmetic shifting](https://en.wikipedia.org/wiki/Arithmetic_shift). ## Ternary Conditional Operator @@ -507,7 +507,7 @@ let y = 1 > 2 ? nil : 3 The static casting operator `as` can be used to statically type cast a value to a type. -If the static type of the value is a subtype of the given type that should be casted to, +If the static type of the value is a subtype of the given type (the "target" type), the operator returns the value as the given type. The cast is performed statically, i.e. when the program is type-checked. @@ -545,8 +545,8 @@ let result = something as Int The conditional downcasting operator `as?` can be used to dynamically type cast a value to a type. The operator returns an optional. -If the value has a run-time type that is a subtype of the given type that should be casted to, -the operator returns the value as the given type, +If the value has a run-time type that is a subtype of the target type +the operator returns the value as the target type, otherwise the result is `nil`. The cast is performed at run-time, i.e. when the program is executed, @@ -572,9 +572,7 @@ let boolean = something as? Bool // `boolean` is `nil` and has type `Bool?` ``` -Downcasting works for nested types (e.g. arrays), -interfaces (if a [resource](resources) interface not to a concrete resource), -and optionals. +Downcasting works for concrete types, but also works e.g. for nested types (e.g. arrays), interfaces, optionals, etc. ```cadence // Declare a constant named `values` which has type `[AnyStruct]`, From 5aec6a3ef90d5d1d9b532dcbbf594ed5ed9d9904 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 27 Jun 2022 14:45:21 -0700 Subject: [PATCH 09/11] Update docs/language/operators.md --- docs/language/operators.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/operators.md b/docs/language/operators.md index 1974e3cbf0..3165b4e687 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -424,7 +424,7 @@ let z: Bool = (x as! Int8) > (y as! Int8) ## Bitwise Operators -Bitwise operators enable the manipulation of individual bits of integers. +Bitwise operators enable the manipulation of individual bits of unsigned and signed integers. They're often used in low-level programming. - Bitwise AND: `a & b` From 97af2ff18bb635ceb9c71b51d671d29ad1fed123 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 27 Jun 2022 14:55:36 -0700 Subject: [PATCH 10/11] move operators --- docs/language/operators.md | 134 +++++++++++++++++++++++++++-- docs/language/values-and-types.mdx | 126 +-------------------------- 2 files changed, 132 insertions(+), 128 deletions(-) diff --git a/docs/language/operators.md b/docs/language/operators.md index 3165b4e687..d2d27d91df 100644 --- a/docs/language/operators.md +++ b/docs/language/operators.md @@ -16,7 +16,7 @@ They are either unary, binary, or ternary. The first operator symbol appears between the first and second value, the second operator symbol appears between the second and third value (infix). -## Assignment Operator +## Assignment Operator (`=`) The binary assignment operator `=` can be used to assign a new value to a variable. @@ -87,7 +87,16 @@ dictionaries[false][3] = 0 //}` ``` -## Swapping Operator +## Force-assignment operator (`<-!`) + +The force-assignment operator (`<-!`) assigns a resource-typed value +to an optional-typed variable if the variable is nil. +If the variable being assigned to is non-nil, +the execution of the program aborts. + +The force-assignment operator is only used for [resource types](resources). + +## Swapping Operator (`<->`) The binary swap operator `<->` can be used to exchange the values of two variables. @@ -503,7 +512,7 @@ let y = 1 > 2 ? nil : 3 ## Casting Operators -### Static Casting Operator +### Static Casting Operator (`as`) The static casting operator `as` can be used to statically type cast a value to a type. @@ -541,7 +550,7 @@ let something: AnyStruct = 1 let result = something as Int ``` -### Conditional Downcasting Operator +### Conditional Downcasting Operator (`as?`) The conditional downcasting operator `as?` can be used to dynamically type cast a value to a type. The operator returns an optional. @@ -587,7 +596,7 @@ let second = values[1] as? Bool // `second` is `true` and has type `Bool?` ``` -### Force-downcasting Operator +### Force-downcasting Operator (`as!`) The force-downcasting operator `as!` behaves like the [conditional downcasting operator `as?`](#conditional-downcasting-operator). @@ -614,6 +623,121 @@ let boolean = something as! Bool // Run-time error ``` +## Optional Operators + +### Nil-Coalescing Operator (`??`) + +The nil-coalescing operator `??` returns +the value inside an optional if it contains a value, +or returns an alternative value if the optional has no value, +i.e., the optional value is `nil`. + +If the left-hand side is non-nil, the right-hand side is not evaluated. + +```cadence +// Declare a constant which has an optional integer type +// +let a: Int? = nil + +// Declare a constant with a non-optional integer type, +// which is initialized to `a` if it is non-nil, or 42 otherwise. +// +let b: Int = a ?? 42 +// `b` is 42, as `a` is nil +``` + +The nil-coalescing operator can only be applied +to values which have an optional type. + +```cadence +// Declare a constant with a non-optional integer type. +// +let a = 1 + +// Invalid: nil-coalescing operator is applied to a value which has a non-optional type +// (a has the non-optional type `Int`). +// +let b = a ?? 2 +``` + +```cadence +// Invalid: nil-coalescing operator is applied to a value which has a non-optional type +// (the integer literal is of type `Int`). +// +let c = 1 ?? 2 +``` + +The type of the right-hand side of the operator (the alternative value) must be a subtype +of the type of left-hand side, i.e. the right-hand side of the operator must +be the non-optional or optional type matching the type of the left-hand side. + +```cadence +// Declare a constant with an optional integer type. +// +let a: Int? = nil +let b: Int? = 1 +let c = a ?? b +// `c` is `1` and has type `Int?` + +// Invalid: nil-coalescing operator is applied to a value of type `Int?`, +// but the alternative has type `Bool`. +// +let d = a ?? false +``` + +### Force Unwrap Operator (`!`) + +The force-unwrap operator (`!`) returns +the value inside an optional if it contains a value, +or panics and aborts the execution if the optional has no value, +i.e., the optional value is `nil`. + +```cadence +// Declare a constant which has an optional integer type +// +let a: Int? = nil + +// Declare a constant with a non-optional integer type, +// which is initialized to `a` if `a` is non-nil. +// If `a` is nil, the program aborts. +// +let b: Int = a! +// The program aborts because `a` is nil. + +// Declare another optional integer constant +let c: Int? = 3 + +// Declare a non-optional integer +// which is initialized to `c` if `c` is non-nil. +// If `c` is nil, the program aborts. +let d: Int = c! +// `d` is initialized to 3 because c isn't nil. + +``` + +The force-unwrap operator can only be applied +to values which have an optional type. + +```cadence +// Declare a constant with a non-optional integer type. +// +let a = 1 + +// Invalid: force-unwrap operator is applied to a value which has a +// non-optional type (`a` has the non-optional type `Int`). +// +let b = a! +``` + +```cadence +// Invalid: The force-unwrap operator is applied +// to a value which has a non-optional type +// (the integer literal is of type `Int`). +// +let c = 1! +``` + + ## Precedence and Associativity Operators have the following precedences, highest to lowest: diff --git a/docs/language/values-and-types.mdx b/docs/language/values-and-types.mdx index af7164debf..3389f8083e 100644 --- a/docs/language/values-and-types.mdx +++ b/docs/language/values-and-types.mdx @@ -101,7 +101,7 @@ and can represent values in the following ranges: The types are independent types, i.e. not subtypes of each other. -See the section about [arithmetic operators](operators#arithmetic) for further +See the section about [arithmetic operators](operators#arithmetic-operators) for further information about the behavior of the different integer types. ```cadence @@ -521,128 +521,8 @@ let xs: [Int?] = [1, nil, 2, nil] let doubleOptional: Int?? = nil ``` -### Nil-Coalescing Operator - -The nil-coalescing operator `??` returns -the value inside an optional if it contains a value, -or returns an alternative value if the optional has no value, -i.e., the optional value is `nil`. - -If the left-hand side is non-nil, the right-hand side is not evaluated. - -```cadence -// Declare a constant which has an optional integer type -// -let a: Int? = nil - -// Declare a constant with a non-optional integer type, -// which is initialized to `a` if it is non-nil, or 42 otherwise. -// -let b: Int = a ?? 42 -// `b` is 42, as `a` is nil -``` - -The nil-coalescing operator can only be applied -to values which have an optional type. - -```cadence -// Declare a constant with a non-optional integer type. -// -let a = 1 - -// Invalid: nil-coalescing operator is applied to a value which has a non-optional type -// (a has the non-optional type `Int`). -// -let b = a ?? 2 -``` - -```cadence -// Invalid: nil-coalescing operator is applied to a value which has a non-optional type -// (the integer literal is of type `Int`). -// -let c = 1 ?? 2 -``` - -The type of the right-hand side of the operator (the alternative value) must be a subtype -of the type of left-hand side, i.e. the right-hand side of the operator must -be the non-optional or optional type matching the type of the left-hand side. - -```cadence -// Declare a constant with an optional integer type. -// -let a: Int? = nil -let b: Int? = 1 -let c = a ?? b -// `c` is `1` and has type `Int?` - -// Invalid: nil-coalescing operator is applied to a value of type `Int?`, -// but the alternative has type `Bool`. -// -let d = a ?? false -``` - -### Force Unwrap (`!`) - -The force-unwrap operator (`!`) returns -the value inside an optional if it contains a value, -or panics and aborts the execution if the optional has no value, -i.e., the optional value is `nil`. - -```cadence -// Declare a constant which has an optional integer type -// -let a: Int? = nil - -// Declare a constant with a non-optional integer type, -// which is initialized to `a` if `a` is non-nil. -// If `a` is nil, the program aborts. -// -let b: Int = a! -// The program aborts because `a` is nil. - -// Declare another optional integer constant -let c: Int? = 3 - -// Declare a non-optional integer -// which is initialized to `c` if `c` is non-nil. -// If `c` is nil, the program aborts. -let d: Int = c! -// `d` is initialized to 3 because c isn't nil. - -``` - -The force-unwrap operator can only be applied -to values which have an optional type. - -```cadence -// Declare a constant with a non-optional integer type. -// -let a = 1 - -// Invalid: force-unwrap operator is applied to a value which has a -// non-optional type (`a` has the non-optional type `Int`). -// -let b = a! -``` - -```cadence -// Invalid: The force-unwrap operator is applied -// to a value which has a non-optional type -// (the integer literal is of type `Int`). -// -let c = 1! -``` - -### Force-assignment operator (`<-!`) - -The force-assignment operator (`<-!`) assigns a resource-typed value to an -optional-typed variable if the variable is nil. -If the variable being assigned to is non-nil, -the execution of the program aborts. - -The force-assignment operator is only used for -[resource types](resources) and the move operator (`<-`), -which are covered in the resources section of this document. +See the [optional operators](operators#optional-operators) section for information +on how to work with optionals. ## Never From 129ac2d96f18c96e70100ec5ed32bf954763ac2c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Thu, 7 Jul 2022 12:46:57 -0700 Subject: [PATCH 11/11] Apply suggestions from code review Co-authored-by: Joshua Hannan --- docs/language/core-events.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/language/core-events.md b/docs/language/core-events.md index 4668c5cd05..c081403026 100644 --- a/docs/language/core-events.md +++ b/docs/language/core-events.md @@ -97,7 +97,7 @@ pub event AccountContractUpdated( | Field | Type | Description | | ----------- | --------- | -------------------------------------------------------- | -| `address` | `Address` | The address of the account the contract gets updated on | +| `address` | `Address` | The address of the account where the updated contract is deployed | | `codeHash` | `[UInt8]` | Hash of the contract source code | | `contract` | `String` | The name of the the contract |