-
Notifications
You must be signed in to change notification settings - Fork 24
FLIP: Allow adding new fields to existing types #295
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
turbolent
wants to merge
8
commits into
main
Choose a base branch
from
bastian/cadence-add-fields
base: main
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
8 commits
Select commit
Hold shift + click to select a range
7430231
add 20220817-add-fields-to-existing-definitions.md
austinkline 136e07f
Apply suggestions from code review
austinkline df1ad5c
Update flips/20220817-add-fields-to-existing-definitions.md
turbolent 3797b81
move to correct directory
turbolent 9ab59b9
move title after front matter, remove trailing whitespace
turbolent 97861b1
update to Cadence 1.0, remove default value proposal
turbolent 7012713
add open questions: field removal and default values
turbolent 6200b4e
add open question regarding already removed fields
turbolent File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,136 @@ | ||
| --- | ||
| status: proposed | ||
| flip: TBD | ||
| authors: Deniz Mert Edincik (deniz@edincik.com), Austin Kline (austin@flowty.io) | ||
| sponsor: Bastian Mueller (bastian.mueller@flowfoundation.org) | ||
| updated: 2022-08-17 | ||
| --- | ||
|
|
||
| # FLIP: Allow adding new fields to existing types | ||
|
|
||
| ## Objective | ||
|
|
||
| This proposed change will allow updating existing types (contracts) with new fields. | ||
|
|
||
| ## Motivation | ||
|
|
||
| One major challenge in smart contract design in Cadence is the inability to add new fields to already deployed types. | ||
| The lack of this functionality means that developers have to resort to brittle workarounds. | ||
| For example, developers may choose to deploy entirely new contracts, | ||
| that are essentially reprints of the original, except with the newly added fields. | ||
| Developers may also choose to | ||
| - Manually storing fields as dictionaries to accommodate future new fields | ||
| - Manually storing new fields in a new, different contract | ||
| - Manually storing new fields in storage | ||
|
|
||
| Each of these workarounds come with their downsides. | ||
| - New contracts lead to complex migrations for applications and sunsetting existing contracts. | ||
| - Storing new data manually is brittle, and leads to harder-to-follow code and added complexity. | ||
| - Factory patterns increase compute since objects must be built at runtime | ||
| and also lose the benefits of type-checking, since the underlying structure is not truly typed. | ||
|
|
||
| ## User Benefit | ||
|
|
||
| Allowing developers to add new fields to existing types as they need them | ||
| will make contract development more focused on the needs of the current version | ||
| as opposed to undue complexity to take future plans into account. | ||
| It will also allow more maintainable contract code with less complex logic when existing contracts get updated. | ||
|
|
||
| ## Design Proposal | ||
|
|
||
| The [contract updatability checking](https://cadence-lang.org/docs/language/contract-updatability) | ||
| is extended to allow new fields to be added to existing types, | ||
| such as contracts, structs, resources, and attachments. | ||
| These new fields must be optional. | ||
|
|
||
| When the added field of an existing stored value is accessed, the result is `nil`. | ||
|
|
||
| For example, assume the following struct type is currently deployed as part of a contract: | ||
|
|
||
| ```cadence | ||
| access(all) | ||
| struct Message { | ||
| access(all) | ||
| let content: String | ||
|
|
||
| init(content: String) { | ||
| self.content = content | ||
| } | ||
| } | ||
| ``` | ||
|
|
||
| We can now add a new field to this struct: | ||
|
|
||
| ```cadence | ||
| access(all) | ||
| struct Message { | ||
| access(all) | ||
| let content: String | ||
|
|
||
| init(content: String) { | ||
| self.content = content | ||
| } | ||
|
|
||
| // An optional new field. Existing instances of Message will have timestamp set to nil when accessed | ||
| // unless they are set at a later date | ||
| access(all) | ||
| let timestamp: UInt64? | ||
| } | ||
| ``` | ||
|
|
||
| ### Limitations | ||
|
|
||
| - This will not allow existing fields to be altered. That is, it is invalid to alter a field's type. | ||
| - This will not allow new fields to be derived from existing ones. | ||
|
|
||
| ### Compatibility | ||
|
|
||
| This should be backwards compatible | ||
|
|
||
| ### User Impact | ||
|
|
||
| - Cadence developers will be able to modify their contract more to their needs | ||
| instead of over-designing with the first launch of their contract(s). | ||
| - If new unforeseen features or fixes require new fields, | ||
| those additions can be kept in the original contract, | ||
| instead of being silo'd off into their own contract. | ||
|
|
||
| ## Prior Art | ||
|
|
||
| N/A | ||
|
|
||
| ## Open Questions | ||
|
|
||
| - Adding fields can only be allowed if it is not possible to re-add previously removed fields. | ||
|
|
||
| One option could be to allow keep allowing to remove existing fields, | ||
| but require them to be "tomb-stoned", | ||
| similar to how [FLIP 275](https://github.com/onflow/flips/issues/275) proposes | ||
| to allow removing existing type definitions. | ||
|
|
||
| For example, field declarations would need to be replaced by e.g. `#removedField(name)`. | ||
|
|
||
| However, how do we handle fields that were already previously removed, | ||
| but are still stored in the object? | ||
| We could clean up existing stored composite values and remove stored fields | ||
| that are not declared in the type. | ||
|
|
||
| - A previous iteration of the proposal also proposed to allow adding non-optional fields, | ||
| by allowing the definition of the added field to provide a *default* value. | ||
|
|
||
| This could be useful for types for which an optional type unnecessarily complicates the type, | ||
| such as for simple types like `Bool`, `String`, `Int`, etc. | ||
|
|
||
| For example, the field added in the example above could be written instead as: | ||
|
|
||
| ```cadence | ||
| let timestamp: UInt64 = 0 | ||
| ``` | ||
|
|
||
| Support for default values could be restricted to just certain types (e.g. `Bool`, `String`, numbers), | ||
| and default value expressions could be restricted to just literals (e.g. `true`, `""`, `0`). | ||
| Further, value expressions could be extended to allow access to `self`, | ||
| and access expressions on it could be allowed. | ||
|
|
||
| The default value functionality would be similar to default values of | ||
| [resource destruction events](https://github.com/onflow/flips/blob/main/cadence/20230811-destructor-removal.md#destruction-events). |
Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
Uh oh!
There was an error while loading. Please reload this page.