owned this note
owned this note
Published
Linked with GitHub
# Enums in FTL
**Author**: @worstell
## Description
We are enriching the FTL type system with enum support.
Enums can be either "value" or "type" enums, where value enums associate names with constant values. Type enums function like sum types or discriminated unions, whereby names are associated with types with no underlying raw value.
Type enums are discussed in futher detail [here](https://hackmd.io/TZqMfuyHTYaXd1gSECbpFg?both).
## Goals
- Enums can be declared in supported runtimes and will be parsed into the FTL schema
- Value enums associate names with constant values
- Numeric and string values are the only supported types for value enums
- Type enums (sum types/discriminated unions) associate names with types. Discussed in further detail [here](https://hackmd.io/TZqMfuyHTYaXd1gSECbpFg?both)
## Design
### Go
Go does not have a concept of enums. In the absence of language builtins, we’ll require an annotation, `//ftl:enum`, to declare an FTL enum. This is necessary to make enums identifiable for schema parsing.
Declaring an enum in a Go module will look as follows:
_Value enum:_
```go
package example
//ftl:enum
type Color string
const (
Red Color = "Red"
Blue Color = "Blue"
Green Color = "Green"
)
```
_Type enum:_
```go!
package example
//ftl:enum
type ScalarOrList interface { tag() }
type Scalar string
func (Scalar) tag() {}
type List []string
func (List) tag() {}
```
Variants are identified on the basis of implementing the discriminator (interface). The discriminator can only contain private methods.
### Kotlin
_Value enum:_
Kotlin supports enum classes which we can leverage directly for declaring value enums as follows:
```kotlin
package ftl.example
enum class Color(name: String) {
RED("Red"),
GREEN("Green"),
BLUE("Blue"),
}
```
_Type enum:_
```kotlin
package ftl.example
data class Scalar(
...
)
data class List(
...
)
@Enum
sealed class SumType {
data class Scalar(
val value: ftl.example.Scalar
) : SumType()
data class Scalar(
val value: ftl.example.List
) : SumType()
}
```
**Note: the `value` field is required to express sum type variants in the Kotlin runtime. It will be detected and used to extract the underlying type.**
In the FTL schema, both of the above cases would appear as follows:
```graphql
module example {
enum Color: String {
Red = "Red"
Blue = "Blue"
Green = "Green"
}
enum ScalarOrList {
Scalar String
List [String]
}
}
```
## Rejected alternatives
### Structured enums
Any hashable type supported in the FTL type system can be an enum value. The initial design leaves the door open to this change in future.
:::info
Enum values must be hashable to make their use as map keys possible. Enum types (transitively), then, cannot have any list/map fields.
:::
In Kotlin, an `enum class` can be constructed with an arbitrary number of values (as any class). If multiple constructor parameters are present, we will synthesize them into a single parameter (wrapping them in an outer type). This is necessary to comply with restrictions of the Go implementation.
Below represents Kotlin user code:
```kotlin
package ftl.exchange
data class CurrencyCode(val code: String)
enum class Country(name: String, currency: CurrencyCode) {
UnitedStates("US", CurrencyCode("USD")),
Australia("AU", CurrencyCode("AUD")),
}
```
And Go:
```go
package exchange
type CurrencyCode {
Code string
}
//ftl:enum
type Country struct {
Name string
Currency CurrencyCode
}
const (
UnitedStates = Country{
Name: "US",
Currency: CurrencyCode{
Code: "USD",
}
}
Australia = Country{
Name: "AU",
Currency: CurrencyCode{
Code: "AUD",
}
}
)
```
Both would appear as follows the FTL schema:
```
module exchange {
data CurrencyCode {
code String
}
enum CountryValue {
name String
currency exchange.CurrencyCode
} {
unitedStates({
name = "US",
currency = {
code = "USD"
}
})
australia({
name = "AU",
currency = {
code = "AUD"
}
})
}
}
```
### Proposal
We will implement restrictive value enums initially. FTL value enums must be either int or string types, which should encompass the vast majority of enum use-cases.