From 5093a8400fab8e52530cb855385a106443bcdb04 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Mon, 9 Feb 2026 15:21:35 -0800 Subject: [PATCH 1/4] add FLIP for adding minOf/maxOf functions to Cadence --- cadence/20260209-minof-maxof-functions.md | 225 ++++++++++++++++++++++ 1 file changed, 225 insertions(+) create mode 100644 cadence/20260209-minof-maxof-functions.md diff --git a/cadence/20260209-minof-maxof-functions.md b/cadence/20260209-minof-maxof-functions.md new file mode 100644 index 00000000..e0d10f13 --- /dev/null +++ b/cadence/20260209-minof-maxof-functions.md @@ -0,0 +1,225 @@ +--- +status: draft +flip: 357 +authors: Bastian Müller (bastian.mueller@flowfoundation.org) +updated: 2026-02-09 +--- + +# FLIP 357: Add minOf and maxOf Functions to Cadence + +## Objective + +Add `minOf` and `maxOf` functions to the Cadence standard library, +providing a convenient way to find the minimum or maximum of two comparable values. + +## Motivation + +Finding the minimum or maximum of two values is a common operation in smart contract development. +Currently, developers must implement this logic manually using conditional expressions: + +```cadence +// Current approach: manual comparison +let smaller = a < b ? a : b +let larger = a > b ? a : b +``` + +While this works, it has several drawbacks: +- **Verbose**: Requires writing the comparison logic repeatedly +- **Error-prone**: Easy to make mistakes with the comparison operators or the ternary expression +- **Less readable**: The intent isn't immediately clear, especially in complex expressions + +Other programming languages provide built-in or standard library functions for this common operation. +Having standard functions improves code readability and reduces the likelihood of errors. + +## User Benefit + +The `minOf` and `maxOf` functions provide several benefits: + +**Improved Readability**: The intent is immediately clear from the function name: +```cadence +let price = minOf(bidPrice, maxPrice) // Clearer than: bidPrice < maxPrice ? bidPrice : maxPrice +``` + +**Reduced Errors**: Eliminates the risk of swapping comparison operators or ternary branches, +or accidentally comparing the wrong variables. + +**Type Safety**: The functions work with any comparable type and ensure both arguments have the same type, +catching type mismatches at compile time. + +**Consistency**: Provides a standard way to perform these operations across all Cadence codebases. + +## Design Proposal + +Add two generic functions to the Cadence standard library that work with any comparable type. + +### Function Signatures + +```cadence +/// Returns the minimum of two values +/// +/// The arguments must be of the same comparable type. +/// +/// Examples: +/// minOf(5, 10) == 5 +/// minOf(10, 5) == 5 +/// minOf(1.5, 2.5) == 1.5 +/// minOf("apple", "banana") == "apple" +/// +access(all) fun minOf(_ a: T, _ b: T): T + +/// Returns the maximum of two values +/// +/// The arguments must be of the same comparable type. +/// +/// Examples: +/// maxOf(5, 10) == 10 +/// maxOf(10, 5) == 10 +/// maxOf(1.5, 2.5) == 2.5 +/// maxOf("apple", "banana") == "banana" +/// +access(all) fun maxOf(_ a: T, _ b: T): T +``` + +### Type Requirements + +The type parameter `T` must be a **comparable type**. +In Cadence, comparable types are those that support comparison operators (`<`, `>`, `<=`, `>=`), +e.g. all concrete number types, strings, characters, booleans, and addresses. + +### Naming Rationale + +The functions are named `minOf` and `maxOf` (rather than `min` and `max`) to avoid naming conflicts: +- Number types already have `min` and `max` fields, + which represent the minimum and maximum values of that type, e.g. `Int8.min` is the minimum value of `Int8` +- Existing contracts may have defined `min` and `max` variables or functions, + so using `minOf` and `maxOf` avoids potential conflicts. + As of 2026-02-09, there are no global functions named `minOf` or `maxOf`, so this naming is safe. +- Kotlin uses the names `minOf` and `maxOf`, see e.g. https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.comparisons/min-of.html + +## Drawbacks + +**Limited to Two Arguments**: The functions only accept two arguments. Finding the minimum or maximum +of more values requires chaining: + +```cadence +let min = minOf(minOf(a, b), c) +``` + +A future enhancement could add variadic versions that accept more than two arguments. + +## Alternatives Considered + +### Alternative 1: Methods + +Add `min(_ other: T)` and `max(_ other: T)` methods to comparable types `T`: + +```cadence +a.min(b) // Returns the minimum of a and b +a.max(b) // Returns the maximum of a and b +``` + +**Pros:** +- Intuitive method syntax +- No naming conflict + +**Cons:** +- Requires many separate implementations (one per comparable type) + +### Alternative 2: Static Methods + +Add `minimum()` and `maximum()` methods to each comparable type: + +```cadence +Int8.minimum(5, 10) +UFix64.maximum(1.5, 2.5) +``` + +**Pros:** +- More discoverable through type-specific documentation +- No naming conflict + +**Cons:** +- More verbose +- Requires many separate implementations (one per comparable type) +- Users must remember type-specific methods instead of a single global function + +## Performance Implications + +The functions are implemented as native functions, +so they will have minimal overhead compared to manual comparisons. + +## Compatibility + +This is a purely additive feature. + +However, to ensure no breaking changes to existing contracts, +the proposal currently assumes that existing contracts do not declare variables or functions named +`minOf` or `maxOf`, which is true as of 2026-02-09. +If a conflict is detected, we may need to consider alternative names, +or an alternative design such as methods on comparable types. + +## Prior Art + +Nearly all major programming languages provide minimum/maximum functions: + +**Python**: + +Global functions that work with any comparable type: + +```python +min(a, b) +max(a, b) +``` + +**JavaScript**: + +Functions that only work with numbers, not with strings or other comparable types: + +```javascript +Math.min(a, b) +Math.max(a, b) +``` + +**Rust**: + +Methods on comparable types: + +```rust +a.min(b) +a.max(b) +``` + +**Swift**: + +Global functions that work with any comparable type: + +```swift +min(a, b) +max(a, b) +``` + +**Kotlin**: + +Global functions that work with any comparable type: + +```kotlin +minOf(a, b) +maxOf(a, b) +``` + +Cadence's design follows the Kotlin naming convention, which also distinguishes comparison functions +from value range constants. + +## Implementation + +An implementation is available at: https://github.com/onflow/cadence/pull/4430 + +## Related Issues + +None + +## Questions and Discussion Topics + +1. Should we rather use method syntax instead of global functions, or static methods on each comparable type? +2. Should we add variants that accept more than two arguments in the future? +3. Should we add `clamp(value, min, max)` as a related utility function? From a8a2a4d05c8569941b699c3a9c1c73cef9e2e48a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 17 Feb 2026 15:28:34 -0800 Subject: [PATCH 2/4] rename to min/max, require import of Comparison contract --- cadence/20260209-minof-maxof-functions.md | 108 ++++++++++++++-------- 1 file changed, 72 insertions(+), 36 deletions(-) diff --git a/cadence/20260209-minof-maxof-functions.md b/cadence/20260209-minof-maxof-functions.md index e0d10f13..fad75530 100644 --- a/cadence/20260209-minof-maxof-functions.md +++ b/cadence/20260209-minof-maxof-functions.md @@ -2,14 +2,14 @@ status: draft flip: 357 authors: Bastian Müller (bastian.mueller@flowfoundation.org) -updated: 2026-02-09 +updated: 2026-02-17 --- -# FLIP 357: Add minOf and maxOf Functions to Cadence +# FLIP 357: Add Comparison Functions to Cadence ## Objective -Add `minOf` and `maxOf` functions to the Cadence standard library, +Add `min` and `max` functions to a new `Comparison` contract in the Cadence standard library, providing a convenient way to find the minimum or maximum of two comparable values. ## Motivation @@ -33,11 +33,13 @@ Having standard functions improves code readability and reduces the likelihood o ## User Benefit -The `minOf` and `maxOf` functions provide several benefits: +The `min` and `max` functions provide several benefits: **Improved Readability**: The intent is immediately clear from the function name: ```cadence -let price = minOf(bidPrice, maxPrice) // Clearer than: bidPrice < maxPrice ? bidPrice : maxPrice +import Comparison + +let price = min(bidPrice, maxPrice) // Clearer than: bidPrice < maxPrice ? bidPrice : maxPrice ``` **Reduced Errors**: Eliminates the risk of swapping comparison operators or ternary branches, @@ -50,7 +52,17 @@ catching type mismatches at compile time. ## Design Proposal -Add two generic functions to the Cadence standard library that work with any comparable type. +Add two generic functions to a new `Comparison` contract in the Cadence standard library +that work with any comparable type. + +### Usage + +```cadence +import Comparison + +let smaller = min(a, b) +let larger = max(a, b) +``` ### Function Signatures @@ -60,24 +72,24 @@ Add two generic functions to the Cadence standard library that work with any com /// The arguments must be of the same comparable type. /// /// Examples: -/// minOf(5, 10) == 5 -/// minOf(10, 5) == 5 -/// minOf(1.5, 2.5) == 1.5 -/// minOf("apple", "banana") == "apple" +/// min(5, 10) == 5 +/// min(10, 5) == 5 +/// min(1.5, 2.5) == 1.5 +/// min("apple", "banana") == "apple" /// -access(all) fun minOf(_ a: T, _ b: T): T +access(all) fun min(_ a: T, _ b: T): T /// Returns the maximum of two values /// /// The arguments must be of the same comparable type. /// /// Examples: -/// maxOf(5, 10) == 10 -/// maxOf(10, 5) == 10 -/// maxOf(1.5, 2.5) == 2.5 -/// maxOf("apple", "banana") == "banana" +/// max(5, 10) == 10 +/// max(10, 5) == 10 +/// max(1.5, 2.5) == 2.5 +/// max("apple", "banana") == "banana" /// -access(all) fun maxOf(_ a: T, _ b: T): T +access(all) fun max(_ a: T, _ b: T): T ``` ### Type Requirements @@ -86,30 +98,57 @@ The type parameter `T` must be a **comparable type**. In Cadence, comparable types are those that support comparison operators (`<`, `>`, `<=`, `>=`), e.g. all concrete number types, strings, characters, booleans, and addresses. -### Naming Rationale +### Naming and Location Rationale -The functions are named `minOf` and `maxOf` (rather than `min` and `max`) to avoid naming conflicts: +The functions are named `min` and `max` and placed in a `Comparison` contract +(rather than being global functions) to avoid naming conflicts: - Number types already have `min` and `max` fields, - which represent the minimum and maximum values of that type, e.g. `Int8.min` is the minimum value of `Int8` -- Existing contracts may have defined `min` and `max` variables or functions, - so using `minOf` and `maxOf` avoids potential conflicts. - As of 2026-02-09, there are no global functions named `minOf` or `maxOf`, so this naming is safe. -- Kotlin uses the names `minOf` and `maxOf`, see e.g. https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.comparisons/min-of.html + which represent the minimum and maximum values of that type, + e.g. `Int8.min` is the minimum value of `Int8` +- This provides better compatibility with existing code: + Existing contracts may have defined `min` and `max` variables. + Placing these functions inside the `Comparison` contract avoids conflicts, + since users only bring them into scope by explicitly importing the contract. ## Drawbacks -**Limited to Two Arguments**: The functions only accept two arguments. Finding the minimum or maximum -of more values requires chaining: +**Requires Import**: Unlike some other standard library functions, +`min` and `max` require an explicit `import Comparison` statement. +This is a minor inconvenience but necessary to avoid naming conflicts with existing code. + +**Limited to Two Arguments**: The functions only accept two arguments. +Finding the minimum or maximum of more values requires chaining: ```cadence -let min = minOf(minOf(a, b), c) +import Comparison + +let minimum = min(min(a, b), c) ``` A future enhancement could add variadic versions that accept more than two arguments. ## Alternatives Considered -### Alternative 1: Methods +### Alternative 1: Global Functions Named `minOf`/`maxOf` + +Use `minOf` and `maxOf` as global standard library functions (no import required): + +```cadence +let smaller = minOf(a, b) +let larger = maxOf(a, b) +``` + +**Pros:** +- No import required +- Kotlin uses these names, see e.g. https://kotlinlang.org/api/core/kotlin-stdlib/kotlin.comparisons/min-of.html + +**Cons:** +- Less familiar naming than `min`/`max` +- Still adds global names that could shadow existing declarations + +This was the initial design but was superseded in favor of `min`/`max` in the `Comparison` contract. + +### Alternative 2: Methods Add `min(_ other: T)` and `max(_ other: T)` methods to comparable types `T`: @@ -125,7 +164,7 @@ a.max(b) // Returns the maximum of a and b **Cons:** - Requires many separate implementations (one per comparable type) -### Alternative 2: Static Methods +### Alternative 3: Static Methods Add `minimum()` and `maximum()` methods to each comparable type: @@ -151,12 +190,9 @@ so they will have minimal overhead compared to manual comparisons. ## Compatibility This is a purely additive feature. - -However, to ensure no breaking changes to existing contracts, -the proposal currently assumes that existing contracts do not declare variables or functions named -`minOf` or `maxOf`, which is true as of 2026-02-09. -If a conflict is detected, we may need to consider alternative names, -or an alternative design such as methods on comparable types. +The functions are scoped to the `Comparison` contract, +so they only affect code that explicitly imports it, +ensuring no breaking changes to existing contracts. ## Prior Art @@ -207,8 +243,8 @@ minOf(a, b) maxOf(a, b) ``` -Cadence's design follows the Kotlin naming convention, which also distinguishes comparison functions -from value range constants. +Cadence's design uses the familiar `min`/`max` naming from Python and Swift, +while scoping the functions to a `Comparison` contract to avoid naming conflicts. ## Implementation From 4f3ccbdee59b1dfbc5212362bbea34973f5cde15 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 17 Feb 2026 15:29:51 -0800 Subject: [PATCH 3/4] rename file to match title --- ...of-maxof-functions.md => 20260209-add-comparison-functions.md} | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename cadence/{20260209-minof-maxof-functions.md => 20260209-add-comparison-functions.md} (100%) diff --git a/cadence/20260209-minof-maxof-functions.md b/cadence/20260209-add-comparison-functions.md similarity index 100% rename from cadence/20260209-minof-maxof-functions.md rename to cadence/20260209-add-comparison-functions.md From c05e5f4be73dce9823c96c6119330f5238acd735 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Tue, 17 Feb 2026 15:45:13 -0800 Subject: [PATCH 4/4] add clamp --- cadence/20260209-add-comparison-functions.md | 65 ++++++++++++++------ 1 file changed, 45 insertions(+), 20 deletions(-) diff --git a/cadence/20260209-add-comparison-functions.md b/cadence/20260209-add-comparison-functions.md index fad75530..6f0ea092 100644 --- a/cadence/20260209-add-comparison-functions.md +++ b/cadence/20260209-add-comparison-functions.md @@ -9,18 +9,21 @@ updated: 2026-02-17 ## Objective -Add `min` and `max` functions to a new `Comparison` contract in the Cadence standard library, -providing a convenient way to find the minimum or maximum of two comparable values. +Add `min`, `max`, and `clamp` functions to a new `Comparison` contract in the Cadence standard library, +providing a convenient way to find the minimum or maximum of two comparable values, +or to clamp a value within a range. ## Motivation -Finding the minimum or maximum of two values is a common operation in smart contract development. +Finding the minimum or maximum of two values, or clamping a value to a range, +are common operations in smart contract development. Currently, developers must implement this logic manually using conditional expressions: ```cadence // Current approach: manual comparison let smaller = a < b ? a : b let larger = a > b ? a : b +let clamped = value < low ? low : (value > high ? high : value) ``` While this works, it has several drawbacks: @@ -28,31 +31,32 @@ While this works, it has several drawbacks: - **Error-prone**: Easy to make mistakes with the comparison operators or the ternary expression - **Less readable**: The intent isn't immediately clear, especially in complex expressions -Other programming languages provide built-in or standard library functions for this common operation. +Other programming languages provide built-in or standard library functions for these common operations. Having standard functions improves code readability and reduces the likelihood of errors. ## User Benefit -The `min` and `max` functions provide several benefits: +The `min`, `max`, and `clamp` functions provide several benefits: **Improved Readability**: The intent is immediately clear from the function name: ```cadence import Comparison let price = min(bidPrice, maxPrice) // Clearer than: bidPrice < maxPrice ? bidPrice : maxPrice +let fee = clamp(computedFee, min: minFee, max: maxFee) // Clearer than: computedFee < minFee ? minFee : (computedFee > maxFee ? maxFee : computedFee) ``` **Reduced Errors**: Eliminates the risk of swapping comparison operators or ternary branches, or accidentally comparing the wrong variables. -**Type Safety**: The functions work with any comparable type and ensure both arguments have the same type, +**Type Safety**: The functions work with any comparable type and ensure all arguments have the same type, catching type mismatches at compile time. **Consistency**: Provides a standard way to perform these operations across all Cadence codebases. ## Design Proposal -Add two generic functions to a new `Comparison` contract in the Cadence standard library +Add three generic functions to a new `Comparison` contract in the Cadence standard library that work with any comparable type. ### Usage @@ -62,12 +66,13 @@ import Comparison let smaller = min(a, b) let larger = max(a, b) +let bounded = clamp(value, min: low, max: high) ``` ### Function Signatures ```cadence -/// Returns the minimum of two values +/// Returns the minimum of two values. /// /// The arguments must be of the same comparable type. /// @@ -79,7 +84,7 @@ let larger = max(a, b) /// access(all) fun min(_ a: T, _ b: T): T -/// Returns the maximum of two values +/// Returns the maximum of two values. /// /// The arguments must be of the same comparable type. /// @@ -90,6 +95,20 @@ access(all) fun min(_ a: T, _ b: T): T /// max("apple", "banana") == "banana" /// access(all) fun max(_ a: T, _ b: T): T + +/// Returns the value clamped to the inclusive range [min, max]. +/// +/// If the value is less than min, min is returned. +/// If the value is greater than max, max is returned. +/// Otherwise, the value itself is returned. +/// The arguments must be of the same comparable type. +/// +/// Examples: +/// clamp(7, min: 1, max: 10) == 7 +/// clamp(0, min: 1, max: 10) == 1 +/// clamp(20, min: 1, max: 10) == 10 +/// +access(all) fun clamp(_ value: T, min: T, max: T): T ``` ### Type Requirements @@ -113,10 +132,10 @@ The functions are named `min` and `max` and placed in a `Comparison` contract ## Drawbacks **Requires Import**: Unlike some other standard library functions, -`min` and `max` require an explicit `import Comparison` statement. +`min`, `max`, and `clamp` require an explicit `import Comparison` statement. This is a minor inconvenience but necessary to avoid naming conflicts with existing code. -**Limited to Two Arguments**: The functions only accept two arguments. +**Limited to Two Arguments for min/max**: The `min` and `max` functions only accept two arguments. Finding the minimum or maximum of more values requires chaining: ```cadence @@ -196,11 +215,12 @@ ensuring no breaking changes to existing contracts. ## Prior Art -Nearly all major programming languages provide minimum/maximum functions: +Nearly all major programming languages provide minimum/maximum/clamp functions: **Python**: -Global functions that work with any comparable type: +Global `min`/`max` functions that work with any comparable type. +No built-in `clamp`, but `max(low, min(value, high))` is the idiomatic form. ```python min(a, b) @@ -209,41 +229,47 @@ max(a, b) **JavaScript**: -Functions that only work with numbers, not with strings or other comparable types: +`min`/`max` functions that only work with numbers. +No built-in `clamp`. ```javascript Math.min(a, b) Math.max(a, b) +Math.max(low, Math.min(value, high)) // clamp idiom ``` **Rust**: -Methods on comparable types: +Methods on comparable types, including `clamp`: ```rust a.min(b) a.max(b) +a.clamp(min, max) ``` **Swift**: -Global functions that work with any comparable type: +Global `min`/`max` functions that work with any comparable type. +`clamp` is available on `Comparable` types as `clamped(to:)`: ```swift min(a, b) max(a, b) +value.clamped(to: low...high) ``` **Kotlin**: -Global functions that work with any comparable type: +Global functions that work with any comparable type, including `coerceIn` for clamping: ```kotlin minOf(a, b) maxOf(a, b) +value.coerceIn(low, high) ``` -Cadence's design uses the familiar `min`/`max` naming from Python and Swift, +Cadence's design uses the familiar `min`/`max`/`clamp` naming (closest to Rust), while scoping the functions to a `Comparison` contract to avoid naming conflicts. ## Implementation @@ -257,5 +283,4 @@ None ## Questions and Discussion Topics 1. Should we rather use method syntax instead of global functions, or static methods on each comparable type? -2. Should we add variants that accept more than two arguments in the future? -3. Should we add `clamp(value, min, max)` as a related utility function? +2. Should we add variadic variants of `min` and `max` that accept more than two arguments in the future?