From fa62cd5355facd7346d72cf02eb4888f63cc47ff Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Thu, 10 Oct 2024 14:42:03 -0700 Subject: [PATCH 1/8] Create 20241010-stringer-interface.md --- cadence/20241010-stringer-interface.md | 104 +++++++++++++++++++++++++ 1 file changed, 104 insertions(+) create mode 100644 cadence/20241010-stringer-interface.md diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md new file mode 100644 index 00000000..7a439c0f --- /dev/null +++ b/cadence/20241010-stringer-interface.md @@ -0,0 +1,104 @@ +--- +status: draft +flip: NNN (set to the issue number) +authors: Raymond Zhang (raymond.zhang@flowfoundation.org) +sponsor: AN Expert (core-contributor@example.org) +updated: 2024-10-10 +--- + +# FLIP NNN: Stringer Interface + +## Objective + +This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. The goal of this FLIP is to simplify the code for converting `AnyStruct` to `String` while allowing for customizability. + +## Motivation + +Currently if a developer wants to accept a value as `AnyStruct` and convert it to a string they have to identify which subtype the value belongs to and call the associated `toString` function. This leads to code such as the following +```cadence +access(all) fun toString(_ value: AnyStruct): String? { + if let stringValue = value as? String { + return stringValue + } else if let boolValue = value as? Bool { + return boolValue ? "true" : "false" + } else if let characterValue = value as? Character { + return characterValue.toString() + } else if let addressValue = value as? Address { + return addressValue.toString() + } else if let pathValue = value as? Path { + return pathValue.toString() + } else if let intValue = value as? Int { + return intValue.toString() + } + ... +} +``` +With the proposed addition, the code could be simplified to +```cadence +access(all) fun toString(_ value: AnyStruct): String? { + if let stringerValue = value as ? {StructStringer} { + return stringerValue.toString() + } +} +``` +The same code above additionally allows for conforming `Struct`s to be converted to `String`s as well which was not previously generalizable. + +## User Benefit + +This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers. It also allows for much cleaner and simpler descriptions of `Struct`s for both developers and end users. + +## Design Proposal + +The proposed interface is as follows + +```cadence +access(all) +struct interface StructStringer { + access(all) + view fun toString(): String +} +``` + +### Drawbacks + +As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. This means that unless it is a primitive type you will have to perform the necessary defensive checks. + +### Alternatives Considered + +An alternative is to have `AnyStruct` itself implement a `toString` function. As a native function there is no longer any risk of malicious code and it still solves the problem of unnecessarily long `AnyStruct` to `String` conversions. The downside of this approach is in limiting customizability for developers. + +### Performance Implications + +None. + +### Dependencies + +None. + +### Engineering Impact + +This change should be simple to implement. + +### Best Practices + +This should become the preferred way of converting `AnyStruct` to `String`. + +### Compatibility + +Proposed changes are backwards compatible. + +### User Impact + +Feature addition, no impact. + +## Related Issues + +string formatting + +## Prior Art + +Many languages have an interface for formatting types as `String` such as + +- [Display trait](https://doc.rust-lang.org/std/fmt/trait.Display.html) in Rust +- `Stringer` in Go + From 0a5787e06851bc96bcec0b5700a8f70095ff5f3a Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Thu, 10 Oct 2024 14:54:21 -0700 Subject: [PATCH 2/8] Update 20241010-stringer-interface.md --- cadence/20241010-stringer-interface.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index 7a439c0f..8e2c322e 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -10,7 +10,7 @@ updated: 2024-10-10 ## Objective -This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. The goal of this FLIP is to simplify the code for converting `AnyStruct` to `String` while allowing for customizability. +This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. One goal of this FLIP is to simplify the code for converting `AnyStruct` to `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. ## Motivation @@ -41,11 +41,11 @@ access(all) fun toString(_ value: AnyStruct): String? { } } ``` -The same code above additionally allows for conforming `Struct`s to be converted to `String`s as well which was not previously generalizable. +The same code above additionally allows for a conforming `Struct` to be converted to a `String` as well which was not previously generalizable. This can be useful for various string formatting functions. ## User Benefit -This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers. It also allows for much cleaner and simpler descriptions of `Struct`s for both developers and end users. +This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers. It also allows for much cleaner and simpler descriptions of a `Struct` for both developers and end users through customizability. It also allows for more powerful string formatting functions. ## Design Proposal @@ -61,11 +61,11 @@ struct interface StructStringer { ### Drawbacks -As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. This means that unless it is a primitive type you will have to perform the necessary defensive checks. +As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. This means that unless the value in question is a primitive type you will have to perform the necessary defensive checks. ### Alternatives Considered -An alternative is to have `AnyStruct` itself implement a `toString` function. As a native function there is no longer any risk of malicious code and it still solves the problem of unnecessarily long `AnyStruct` to `String` conversions. The downside of this approach is in limiting customizability for developers. +An alternative is to have `AnyStruct` itself implement a `toString` function. As a native function there is no longer any risk of malicious code and it still solves the first goal. Additionally, it still allows for more powerful string formatting. The downside of this approach is in limiting customizability for developers. ### Performance Implications From d74d0be73eb5d62fa61f306436977cec8a6afeec Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Mon, 21 Oct 2024 15:10:40 -0400 Subject: [PATCH 3/8] Update 20241010-stringer-interface.md --- cadence/20241010-stringer-interface.md | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index 8e2c322e..5e1cb936 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -1,16 +1,16 @@ --- status: draft -flip: NNN (set to the issue number) +flip: 293 authors: Raymond Zhang (raymond.zhang@flowfoundation.org) -sponsor: AN Expert (core-contributor@example.org) -updated: 2024-10-10 +sponsor: Supun Setunga (supun.setunga@flowfoundation.org) +updated: 2024-10-21 --- -# FLIP NNN: Stringer Interface +# FLIP 293: Stringer Interface ## Objective -This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. One goal of this FLIP is to simplify the code for converting `AnyStruct` to `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. +This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. ## Motivation @@ -41,11 +41,11 @@ access(all) fun toString(_ value: AnyStruct): String? { } } ``` -The same code above additionally allows for a conforming `Struct` to be converted to a `String` as well which was not previously generalizable. This can be useful for various string formatting functions. +Additionally a conforming `Struct` can be converted to a `String` in the same function which was not previously possible. This can be useful for various string formatting functions. ## User Benefit -This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers. It also allows for much cleaner and simpler descriptions of a `Struct` for both developers and end users through customizability. It also allows for more powerful string formatting functions. +This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers, especially for debugging and providing user readable descriptions. It also allows for more powerful string formatting functions. ## Design Proposal @@ -61,11 +61,11 @@ struct interface StructStringer { ### Drawbacks -As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. This means that unless the value in question is a primitive type you will have to perform the necessary defensive checks. +As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. ### Alternatives Considered -An alternative is to have `AnyStruct` itself implement a `toString` function. As a native function there is no longer any risk of malicious code and it still solves the first goal. Additionally, it still allows for more powerful string formatting. The downside of this approach is in limiting customizability for developers. +An alternative is to have `AnyStruct` itself implement a `toString` function. As a native function there is no longer any risk of malicious code and it still solves the first goal. Additionally, it still allows for more powerful string formatting. The downside of this approach is in limiting customizability for developers. ### Performance Implications @@ -81,7 +81,7 @@ This change should be simple to implement. ### Best Practices -This should become the preferred way of converting `AnyStruct` to `String`. +Reduce code size in converting `AnyStruct` to `String`. ### Compatibility @@ -93,7 +93,7 @@ Feature addition, no impact. ## Related Issues -string formatting +[string formatting](https://github.com/onflow/cadence/issues/3579) ## Prior Art From dd86510bed8108bcbd584666109961a86b7ba13f Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Wed, 23 Oct 2024 10:01:21 -0400 Subject: [PATCH 4/8] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20241010-stringer-interface.md | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index 5e1cb936..f9e40445 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -10,7 +10,7 @@ updated: 2024-10-21 ## Objective -This flip proposes the addition of a struct interface `StructStringer` which all string-convertible structs will implement. One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. +This FLIP proposes the addition of a struct interface `StructStringer` to Cadence, which all string-convertible structs will implement. One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. ## Motivation @@ -36,12 +36,12 @@ access(all) fun toString(_ value: AnyStruct): String? { With the proposed addition, the code could be simplified to ```cadence access(all) fun toString(_ value: AnyStruct): String? { - if let stringerValue = value as ? {StructStringer} { + if let stringerValue = value as? {StructStringer} { return stringerValue.toString() } } ``` -Additionally a conforming `Struct` can be converted to a `String` in the same function which was not previously possible. This can be useful for various string formatting functions. +Additionally a conforming struct can be converted to a `String` in the same function which was not previously possible. This can be useful for various string formatting functions. ## User Benefit @@ -99,6 +99,7 @@ Feature addition, no impact. Many languages have an interface for formatting types as `String` such as -- [Display trait](https://doc.rust-lang.org/std/fmt/trait.Display.html) in Rust -- `Stringer` in Go +- [`Display` trait](https://doc.rust-lang.org/std/fmt/trait.Display.html) in Rust +- [`Stringer` interface](https://pkg.go.dev/fmt#Stringer) in Go +- [`CustomStringConvertible`](https://developer.apple.com/documentation/swift/customstringconvertible) in Swift From 85e9c20c9c7627ad356bff8b5a9d803ae6a48105 Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Wed, 23 Oct 2024 10:08:57 -0400 Subject: [PATCH 5/8] Add reasoning on Struct prefix. --- cadence/20241010-stringer-interface.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index f9e40445..ebc695a0 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -59,6 +59,8 @@ struct interface StructStringer { } ``` +The prefix `Struct` is present to make it clear this is a struct interface and in the future a resource interface can be added. + ### Drawbacks As with all user-defined types there are risks associated with calling someone else's `toString` function such as panic or gas usage concerns that developers need to be aware of. From c82f99e31d362500f8b1b8d70c55ef968b237415 Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Wed, 23 Oct 2024 12:46:02 -0400 Subject: [PATCH 6/8] Clarify purpose of interface. --- cadence/20241010-stringer-interface.md | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index ebc695a0..c5167eae 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -10,7 +10,9 @@ updated: 2024-10-21 ## Objective -This FLIP proposes the addition of a struct interface `StructStringer` to Cadence, which all string-convertible structs will implement. One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. +This FLIP proposes the addition of a struct interface `StructStringer` to Cadence, which all string-convertible structs will implement. Note that some languages distinguish between a "human-readable representation" and a "debug representation". The purpose of the `StructStringer` interface is to help with providing "human-readable representations" of `AnyStruct` and is separate from the "debug representation" which already exists. + +One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. ## Motivation @@ -45,7 +47,7 @@ Additionally a conforming struct can be converted to a `String` in the same func ## User Benefit -This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers, especially for debugging and providing user readable descriptions. It also allows for more powerful string formatting functions. +This will significantly streamline the process of converting `AnyStruct` values to `String` which is useful for developers, in providing human readable descriptions. It also allows for more powerful string formatting functions. ## Design Proposal From d81fb7a03791cd0402af5a9152418c1c8638595b Mon Sep 17 00:00:00 2001 From: Raymond Zhang Date: Wed, 23 Oct 2024 17:10:34 -0400 Subject: [PATCH 7/8] Update cadence/20241010-stringer-interface.md MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Bastian Müller --- cadence/20241010-stringer-interface.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index c5167eae..c43064bf 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -6,7 +6,7 @@ sponsor: Supun Setunga (supun.setunga@flowfoundation.org) updated: 2024-10-21 --- -# FLIP 293: Stringer Interface +# FLIP 293: StructStringer Interface ## Objective From 47d1621ef79dce49cb1d2083e53d081b427c201c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bastian=20M=C3=BCller?= Date: Wed, 30 Oct 2024 09:52:27 -0700 Subject: [PATCH 8/8] approve --- cadence/20241010-stringer-interface.md | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/cadence/20241010-stringer-interface.md b/cadence/20241010-stringer-interface.md index c43064bf..104a4d8b 100644 --- a/cadence/20241010-stringer-interface.md +++ b/cadence/20241010-stringer-interface.md @@ -1,9 +1,9 @@ --- -status: draft +status: approved flip: 293 authors: Raymond Zhang (raymond.zhang@flowfoundation.org) -sponsor: Supun Setunga (supun.setunga@flowfoundation.org) -updated: 2024-10-21 +sponsor: Supun Setunga (supun.setunga@flowfoundation.org) +updated: 2024-10-30 --- # FLIP 293: StructStringer Interface @@ -12,7 +12,7 @@ updated: 2024-10-21 This FLIP proposes the addition of a struct interface `StructStringer` to Cadence, which all string-convertible structs will implement. Note that some languages distinguish between a "human-readable representation" and a "debug representation". The purpose of the `StructStringer` interface is to help with providing "human-readable representations" of `AnyStruct` and is separate from the "debug representation" which already exists. -One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. +One goal of this FLIP is to simplify the process for representing `AnyStruct` as a `String`. Secondly, a customizable `toString` will be useful for future string formatting such as string interpolation with this interface. ## Motivation @@ -35,7 +35,7 @@ access(all) fun toString(_ value: AnyStruct): String? { ... } ``` -With the proposed addition, the code could be simplified to +With the proposed addition, the code could be simplified to ```cadence access(all) fun toString(_ value: AnyStruct): String? { if let stringerValue = value as? {StructStringer} { @@ -54,7 +54,7 @@ This will significantly streamline the process of converting `AnyStruct` values The proposed interface is as follows ```cadence -access(all) +access(all) struct interface StructStringer { access(all) view fun toString(): String