[Pitch] `@OptionSet` macro

I like this!

If the code I would normally write is this:

struct ShippingOptions: OptionSet {
  let rawValue: Int
  
  static let nextDay = Self(rawValue: 1 << 0)
  static let secondDay = Self(rawValue: 1 << 1)
  static let priority = Self(rawValue: 1 << 2)
  static let standard = Self(rawValue: 1 << 3)
}

Then the macro directly reduces the boilerplate, letting me write a strict subset of the code I would normally have to write:

@OptionSet struct ShippingOptions {
  static let nextDay: Self
  static let secondDay: Self
  static let priority: Self
  static let standard: Self
}

This seems like a good general guideline for macros that share the same name as a protocol, like @OptionSet: the macro should help reduce the boilerplate of a typical, "happy path" conformance.

The current proposed solution does strictly reduce the boilerplate of the "private enum" style of implementing an OptionSet, but I'm not sure how common that particular style is. It seems better to me to spend the unique @OptionSet name on a macro that implements the conformance as directly as possible.


As some related prior art, SwiftUI has a few cases of concepts that come in both enum and option set forms, e.g. Edge and Edge.Set. In those cases, the enum is the outer type, with the option set declared as the inner .Set type.

The "enum wrapping an option set" pattern would be another alternative/future direction to consider for the proposal, in cases where a developer wants to create and expose both an enum and option set representation of the same concept, e.g.

@OptionSetRepresentable // <- straw man name
enum ShippingOption {
  case nextDay
  case secondDay
  case priority
  case standard
}

which would expand to a nested ShippingOption.Set option set type.

I like that pattern because it's generally more intuitive to declare and document an enum, so that's what I'd likely declare first and want to have as the top-level type in my API. It also mirrors the OptionSet name by using an <Option>.Set naming pattern.

(To be clear, this approach is complementary with the @OptionSet macro, not a mutually-exclusive alternative — if you only want an option set, and want to keep the enum representation private, then use @OptionSet.)

9 Likes