[Pitch] `@OptionSet` macro

I'm actually starting to see the potential rationale behind creating a new type for option sets.

Option sets sit in an awkward space between enums and structs, as evidenced by the fact that the proposal would require two separate types to perform its goal. Currently, we have a set of values that have a small memory footprint and statically-allocated size. There's awkward boilerplate when it comes to constructing the bitmask part of it, however. In a lot of cases it would also be nice to be able to switch over individual options within that set.

This proposal addresses the awkward boilerplate, but adds an awkward extra type for all the individual cases. This could be used for exhaustive switch statements, but it would be preferable, IMO, if the individual options and the bitmask were unified in a single type.

Although I didn't at first, I actually find myself agreeing with @davedelong that we should instead investigate some alternative. I wouldn't be opposed to a new value type alongside struct and enum.

optionset MyOptions: UInt64 {
  case fast = 0 // refers to bit offset
  case reliable = 1
}

/*
synthesized:
extension MyOptions {
  // both of these could return nil with invalid values
  init?(rawValue: UInt64) { ... }
  init?(bitOffset: some BinaryInteger) { ... }
}
*/

let emptyOptions: MyOptions = []
var bitOffsetOption = MyOptions(bitOffset: 1) // ?[.reliable] 
var multipleOptions = MyOptions(rawValue: 3) // ?[.reliable, .fast]
bitOffsetOption = MyOptions(bitOffset: 42) // nil
multipleOptions = MyOptions(rawValue: 42) // nil

optionset MyNonCompilingOptions: UInt8 {
  case a, b, c, d, e, f, g, h, i // Error: too many options for memory layout
  case j = 9 // Error: bit offset too large
}

There would be a lot to work out with specifics (eg, semantics of switching through an optionset that contains multiple values), but I think this would be preferable to the band-aid solution of a macro.

8 Likes