Skip to content

Commit

Permalink
add FLIP for removing type requirements
Browse files Browse the repository at this point in the history
  • Loading branch information
dsainati1 committed Jul 11, 2023
1 parent 9e954f8 commit be1f8d2
Showing 1 changed file with 126 additions and 0 deletions.
126 changes: 126 additions & 0 deletions cadence/20230711-remove-type-requirements.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,126 @@
---
status: draft
flip: NNN (do not set)
authors: Daniel Sainati ([email protected])
sponsor: Daniel Sainati ([email protected])
updated: 2023-07-11
---

# Remove Type Requirements from Cadence

## Objective

Currently, it is possible for a contract interface to declare a nested concrete type within itself.
When this occurs, it requires any contracts that implement this interface to also provide an implementation
of that nested concrete type. So, for example, given the following contract definition:

```cadence
access(all) contract interface Outer {
access(all) resource Nested {
access(all) field: Int
}
}
access(all) contract ExampleOuter: Outer {
access(all) resource Nested {
access(all) var field: Int
init(field: Int) {
self.field = field
}
}
}
```

The definition of `Outer` includes a definition of a concrete type `Nested`.
However, note that this concrete type is actually defined like an interface, and includes no implementation.
Instead, this definiton of `Nested` requires any contracts implementing `Outer` to provide a definition of `Nested`
that conforms to the specification provided in `Outer`. This is called a nested type requirement.

## Motivation

Type requirements are a very complex feature, both in their use and their implementation.

In their usage, they behave differently than any other concrete type definitions,
and as such are a source of confusion for users.
Additionally they result in a large amount of boilerplate code for any contracts that implement
these interfaces, as they need to implement all of the type requirements, even when they are not
required for the specific functionality of the implementing contract.

From the implementation side,
they require a great deal of special-cased behavior that complicates the Cadence codebase.

Removing this feature would simplify the language both for the users and the implementors,
and with the addition of the ability to emit events direclty from interfaces,
the primary use-case for this feature (requiring contracts to define certain events) has been removed.

## User Benefit

This will simplify the language for users.

## Design Proposal

This will require two related changes to the codebase:

### Defining Concrete Events in Interfaces

First, the semantics of declaring an event in an interface will need to be changed.
Currently, a definition such as

```cadence
access(all) contract interface Interface {
access(all) event Foo()
}
```

does not declare a concrete event type `Foo`, but rather specifies a type requirement enforcing
that all concrete contracts implementing `Interface` also specify a `Foo` event type.
This is unnecessary boilerplate, since implementing `Interface` gives the implementer no choice
in how they implement `Foo`; they must simply copy the definition of `Foo` from the interface
to the concrete contract.

We can remove this unnecessary code duplication by changing the semantics of this code to instead
define a concrete event type `Foo`, which can be referenced as such within `Interface` (i.e. if it is
emitted by a condition or default implementation of one of `Interface`'s functions), or as a qualified
type `Interface.Foo` elsewhere.

### Ban Non-Event Concrete Type Declarations in Interfaces

Coupled with this change to events would be a ban on definitions of all other concrete types inside interfaces.
Specifically, resources, structs, enums, and attachments would no longer be declarable inside of interfaces.
Attempting to declare a concrete type in an interface would result in a static error.

Removing the ability to define a non-event concrete type in an interface,
coupled with the change to the semantics of event definitions, would mean that the necessary first step of
creating a type requirement (a concrete type definition in a contract interface) would become impossible,
thus allowing us to remove all references and uses of this feature from the Cadence codebase.

### Drawbacks

This will break any code that currently relies on nested type requirements.

### Alternatives Considered

It is possible to leave this feature present in the language without blocking anything else.
However, the release of Stable Cadence is our only chance to remove this complex legacy feature,
and if we don't do it now we will be forced to support it indefinitely.

It is also possible to change all concrete type declarations in interfaces to instead declare
a qualified concrete type, instead of just having events behave this way and banning the definitions
for other types. This would extend the changes to the semantics for event definitions to all concrete types.

### Tutorials and Examples

Existing tutorials or examples that make use of type requirements will need to be updated.

### User Impact

This will break a large amount of existing user code.
Existing contracts that provide implementations for type requirements will not be updatable (since nested
type definitions cannot be removed), however these themselves will not break. Rather, the upstream
contract interfaces that provide the type requirements will instead break. These will be removable
as they are not actually nested type definitions.

## Questions and Discussion Topics

* Between banning all non-event nested concrete definitions and changing them to behave like the proposed
new event definitions, which do we prefer?

0 comments on commit be1f8d2

Please sign in to comment.