# L-shaped enums

**URL:** <https://forums.swift.org/t/l-shaped-enums/66661>\
**Category:** Using Swift\
**Created:** [August 8, 2023, 8:50pm UTC](https://forums.swift.org/t/l-shaped-enums/66661 "2023-08-08T20:50:43Z")\
**Posts on this page:** 7\
**Page:** 1

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [August 8, 2023, 8:50pm UTC](https://forums.swift.org/t/l-shaped-enums/66661/1 "2023-08-08T20:50:43Z")

</div>

for lack of a better term, i have a lot of “L-shaped” enums that have some varying payload types, and some common payload types.

here’s an example:

```swift
extension ServerDelegate
{
    enum Request:Sendable
    {
        case get (Get, EventLoopPromise<ServerResponse>)
        case post (Post, EventLoopPromise<ServerResponse>)
        case delete (Delete, EventLoopPromise<ServerResponse>)
    }
}
extension ServerDelegate.Request
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

```

there are problems with this layout:

- hard to access the common field (`EventLoopPromise<ServerResponse>`) without `switch`-ing on the enum

- hard to switch on the actual variant payload because you have to `_`-ignore the common fields

there is an obvious refactor here, which is lift the variant payload to another nested type:

```swift
extension ServerDelegate
{
    struct Request:Sendable
    {
        let operation:Operation
        let promise:EventLoopPromise<ServerResponse>
    }
}
extension ServerDelegate.Request
{
    enum Operation:Sendable
    {
        case get (Get)
        case post (Post)
        case delete (Delete)
    }
}
extension ServerDelegate.Request.Operation
{
    enum Get { ... }
    enum Post { ... }
    enum Delete { ... }
}

```

but this feels like a lot of nesting and a lot of (excessive?) type structure proportional to how complex the thing i am trying to model is. and the `ServerDelegate.Request.Operation.Get`, `ServerDelegate.Request.Operation.Post`, etc. enums may themselves have yet more nested structure.

what are our alternatives?

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [August 8, 2023, 9:12pm UTC](https://forums.swift.org/t/l-shaped-enums/66661/2 "2023-08-08T21:12:31Z")

</div>

> [@taylorswift](#):
>
> but this feels like a lot of nesting and a lot of (excessive?) type structure proportional to how complex the thing i am trying to model is

I'm curious what feels excessive to you about this latter option, nesting aside. It seems to me to quite directly model a type which contains a common payload and one of several variant payloads.

In any case, another reshaping I can see (starting from your first snippet) would be to push the `EventLoopPromise` down into each of the variant payloads, and then provide a convenience `promise` getter on the `Request` enum so that the switching only has to be done in one spot, and everywhere else you can access `request.promise` directly.

---

<div class="post-metadata">

**Author:** ![taylorswift](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/taylorswift/32/43413_2.png) [@taylorswift](https://forums.swift.org/u/taylorswift)\
**Post date:** [August 8, 2023, 9:19pm UTC](https://forums.swift.org/t/l-shaped-enums/66661/3 "2023-08-08T21:19:50Z")

</div>

> [@Jumhyn](#):
>
> I'm curious what feels excessive to you about this latter option, nesting aside. It seems to me to quite directly model a type which contains a common payload and one of several variant payloads.

there are a lot of namespace dots to type, and a lot of concentric `.init(.init(.init(.init( ... )))`s to scan when reading code that traffics in this stuff.

> [@Jumhyn](#):
>
> In any case, another reshaping I can see (starting from your first snippet) would be to push the `EventLoopPromise` down into each of the variant payloads, and then provide a convenience `promise` getter on the `Request` enum so that the switching only has to be done in one spot, and everywhere else you can access `request.promise` directly.

the difficulty with pushing the `EventLoopPromise` into the variant types is that the promise value has to be passed along by every `init` layer, and the initializers already have lots of parameters. moreover, many of the initializers are failable (and creating a promise is an expensive operation), so i want the initialization of `ServerDelegate.Request.Operation.Get`, etc. to succeed first before asking the event loop group to mint a new `EventLoopPromise`.

---

<div class="post-metadata">

**Author:** ![Jumhyn](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/jumhyn/32/3891_2.png) [@Jumhyn](https://forums.swift.org/u/Jumhyn)\
**Post date:** [August 8, 2023, 9:33pm UTC](https://forums.swift.org/t/l-shaped-enums/66661/4 "2023-08-08T21:33:05Z")

</div>

Well, the namespace dots are a result of the nesting which isn't really fundamental to the type structure here. It also seems reasonable to provide convenience APIs to deal with some of the `.init` soup, e.g.:

```swift
extension Request {
  static func get(url: URL, params: [String: String], mintPromise: () -> EventLoopPromise) -> Self { ... }
}

```

---

<div class="post-metadata">

**Author:** ![tera](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/tera/32/38201_2.png) [@tera](https://forums.swift.org/u/tera)\
**Post date:** [August 9, 2023, 12:52am UTC](https://forums.swift.org/t/l-shaped-enums/66661/5 "2023-08-09T00:52:36Z")

</div>

> [@taylorswift](#):
>
> .init(.init(.init(.init( ... )))

I love writing that as it requires no thinking and very fast to type due to autocomplete. And then I almost always regret writing that when it comes to reading.

---

<div class="post-metadata">

**Author:** ![hgraves](https://avatars.discourse-cdn.com/v4/letter/h/ec9cab/32.png) [@hgraves](https://forums.swift.org/u/hgraves)\
**Post date:** [August 10, 2023, 6:54am UTC](https://forums.swift.org/t/l-shaped-enums/66661/6 "2023-08-10T06:54:18Z")

</div>

For clients who adopt the API from the example in your original post, might they be required to ultimately `switch` over the cases such as

```swift

// MyMiddleWare.swift

func routeRequestOperation(request: ServerDelegate.Request.Operation) { 
switch request {….}
}

```

Assuming ServerDelegate is exposed in some sort of API / library / framework, if I’m a client with client code that looks like this, it’s up to me to have a `default` case right? Assuming that later on it may become likely that your API introduces a new request type, which my casing must address?

It makes me wonder if `enum` and the proposed nesting is the right approach to this family of problems.

For example if a case was removed, and consumer side didn’t have a default case, this would break the consumer project. Same if a case was added…

However if this were a protocol, the deletes _might_ be safe but the additional functionality is likely not to be safe, assuming that someone could be implementing the protocol on their own (adding functionality requirements and constraints = breaking everyone who currently doesn’t conform to that new set of requirements). Deleting a requirement on the other hand seems safe but is still risky….

If it was a class, assuming no inheritance, I think that additional behavior being added is fine in all cases however deletes are not necessarily safe.

I think that what I’m getting at is:  
Is `enum` the right type “all of the way down” ? Starting with `enum` casing on `Request` and into `Operation` etc. Do the expectations of the type hold continuously over all of those nested sets (nested cases)

Ultimately I think that we end up with layers of assumptions based on the underlying types that have been chosen to represent each layer. Be it a `struct` or nested `enum` or adoptable `protocol` etc each type offers some way to constraint or enhance the expression of the problem. And it seems natural as well as understandable to question if `enum` nesting is appropriate for representing this problem.

I do think it’s fine to nest the enums but it does also depend on if the type can hold safely across all of the intended behaviors for the APi

---

<div class="post-metadata">

**Author:** ![Dmitriy\_Ignatyev](https://sea2.discourse-cdn.com/swift/user_avatar/forums.swift.org/dmitriy_ignatyev/32/11340_2.png) [@Dmitriy\_Ignatyev](https://forums.swift.org/u/Dmitriy_Ignatyev)\
**Post date:** [August 14, 2023, 3:22pm UTC](https://forums.swift.org/t/l-shaped-enums/66661/7 "2023-08-14T15:22:10Z")

</div>

> [@taylorswift](#):
>
> hard to access the common field (`EventLoopPromise<ServerResponse>`) without `switch`-ing on the enum

What about this variant?

```swift
struct Request: Sendable {
  let promise: EventLoopPromise<ServerResponse>
  let method: Method

  enum Method: Sendable {
    case get(Get)
    case post(Post)
    case delete(Delete)
  }
}
    

```
