cadence
cadence copied to clipboard
Adding default implementations to interface methods
Issue To Be Solved
In order to evolve contracts and standards like the NFT contract Interface having some way to specify the default behavior of a interface method is needed.
Say you want to add a getName(): String
method to all INFT types. In order to do that safely the sanes way is IMHO to add support for default implementations.
Suggested Solution
Interface methods can today contain pre and post blocks. One suggestion from bluesign is that they can also contain a default block. And when implementing an interface methods that have a default block can be left unimplemented in the implementing code
Context
See here for context https://github.com/onflow/flow-nft/issues/9
Notes
-
Current state: We already have support for declaring pre/post-conditions in interface function bodies and linking them into execution
-
We want to keep support for function declarations in interfaces that have no body, or just pre and post conditions
struct interface X { fun foo() { only pre, post ... } fun bar() }
-
We want to add support for function declarations in interfaces with a body
struct interface X { fun foo() {} }
-
Parsing (in
runtime/parser2
):- Already done: Interface declarations are parsed like composite declarations
- Add test
-
Checking (in
runtime/sema
):- Allow function bodies in interface
- see
Checker.checkInterfaceSpecialFunctionBlock
- Change tests to be valid, e.g.
TestCheckInvalidInterfaceWithFunctionImplementation
- Change test names
- see
- Check the interface function bodies:
-
Checker.checkInterfaceFunctions
callsvisitFunctionDeclaration
:-
mustExit
flag needs rename/change, e.g. OK if there are only pre and post conditions -
declare
should be true (?), as other functions should be able to refer to the function -
checkResources
should be true
-
-
- Composite conforming to interface
- Note: Implicit conformance when interface requires concrete implementation
- see
Checker.checkCompositeConformance
- Missing function? check if interface member is function, and if so if it has a block, not a missing member
- report of
MissingFunctionBodyError
should stay - Record which interface type has default implementation for composite function. Needed to link in default implementation at run-time in interpreter
- Edge case: Report an error when multiple interfaces provide a default implementation
- Checker/sema tests are in
runtime/tests/checker
- Allow function bodies in interface
-
Execution:
- Composite functions are already wrapped with pre/post conditions of the interface
- A wrapper is
type FunctionWrapper = func(inner FunctionValue) FunctionValue
.- Pseudocode:
return func(body func) { preConditions() body() postConditions() }
- Pseudocode:
- See
Interpreter.functionConditionsWrapper
- How is interface code linked into composite?
=> record which interface for which function provides the default implementation in checker! -> semantic
-
CompositeValue.InitializeFunctions
links in functions for composite - Declared in ... EOF
-
merge after secure cadence release
Would it be possible to reconsider and have this as part of that release? If we can do that and at the same time implement getViews and resolveViews in NFT contract it would solve the linking problem that is a very hard one.
The code for the release was feature frozen a few months ago and then received security audits, so unfortunately we will not be able to get it into this release, but will definitely try to get it into the next release, given that is is now complete.
good to go once we verify there are no security implications, might need adding more test cases.