Re-pitch: Deriving collections of enum cases

Nit: if you want to call it `ValueEnumerable`, then this should be
`DefaultValueCollection`.

I used `DefaultCaseCollection` because, although the protocol can work
with any type to return its values, this type can only work with enums and
only returns their cases. `ValueEnumerable` could be sensibly applied to
`Int`; `DefaultCaseCollection` could not.

Because of how you've chosen to implement `DefaultCaseCollection`, or do
you mean to say that you deliberately want a design where types other than
enums do not share the default return type?

More generally though, I can see the appeal of allowing `Int` to conform
to `ValueEnumerable`, but I've got a feeling that this is headed rapidly in
the direction of overengineering a feature without a good rationale for the
additional complexity. The stated use case is to enumerate the cases of an
enum, and any additional complexity above that should stand on its own
merit. I disagree quite vehemently that protocols should be "as general as
possible"; rather, they exist to enable useful generic algorithms and
should be as _useful_ as possible. There is a happy medium beyond which
overengineering the design makes a protocol markedly less
usable/approachable for the sake of enabling rare functionality.

Tony's "no more specific than they need to" language applies here. The way
I see it is this:

* `Bool` is not an enum, but it could be usefully conformed to
`ValueEnumerable`. Why should we prevent that?
* A type with two independently-switchable `Bool`s—say, `isMirrored` and
`isFlipped`—could be usefully conformed to `ValueEnumerable`. Why should we
prevent that?
* Having integer types conform to `ValueEnumerable` with `static let
allValues = Self.min...Self.max` could be useful. Why should we prevent
that?

I'd say you're looking at it the wrong way. We're not *preventing*
anything. We're adding a feature, and the question is, why should we *add*
more than is justified by the use case?

Is there a clamor for enumerating the two possible values of `Bool`? If so,
is that not an argument instead to make `Bool` an enum and not a struct
under the hood?
Is there a clamor for enumerating the possible values of a type with two
independently switchable `Bool`s? If so, is that not an argument to make
`Bool` a valid raw value type? (There is already a bug report to make
tuples of raw value types valid raw value types themselves.)
Why is it useful for (fixed-width) integer types to conform to
`ValueEnumerable`? What use cases, exactly, would that enable that are not
possible now?

And at the same time, a small, specialized collection type _also_ helps
with our intended use case in some ways (while admittedly making things
more difficult in others). So I think the more general design, which also
works better for our intended use case, is the superior option.

Along the lines of user ergonomics, I would advocate for as many enums as
possible to conform without explicit opt-in. It's true that we are moving
away from such magical designs, and for good reason, but the gain here of
enums Just Working(TM) for such a long-demanded feature has, I would argue,
more benefits than drawbacks. To my mind, the feature is a lot like
`RawRepresentable` in several ways, and it would be defensible for an equal
amount of magic to be enabled for it.

But `RawRepresentable` *doesn't* get automatically added to all enums—you
explicitly opt in, albeit using a special sugar syntax. No, I think opt-in
is the right answer here. We might be able to justify adding sugar to
opt-in, but I can't actually think of a way to make opting in easier than
conforming to a protocol and letting the complier synthesize the
requirements.

Yes, you're right that `RawRepresentable` conformance *doesn't* get
automatically added in, but there exists special sugar which makes the end
result indistinguishable. By this I mean that the user gets
`RawRepresentable` conformance without ever writing `Foo :
RawRepresentable` anywhere (and neither do they write `Foo : Bar` where
`Bar` is in turn `RawRepresentable`).

(This is also important for library evolution. A public enum may not want

to promise that its values will always be enumerable—for instance, it might
add a case with a non-enumerable associated type in the future. Since
conformances are always as public as the type itself, we can't have this
feature be opt-out without moving away from using a protocol.)

This is, in fact, a perfect opportunity to bring up a question I've been
leaving implicit. Why not explore moving away from using a protocol? The
proposed protocol has no syntactic requirements, and when constrained only
the use case of enums, it has essentially no semantic requirements either.
It seems that it's only because we've committed to using a protocol that
we've opened up this exploration of what it means semantically to be
`ValueEnumerable`, and how to generalize it to other types, and how to
design the return type of the synthesized function, etc.

What if some attribute would simply make the metatype conform to `Sequence`
(or, for that matter, `BidirectionalCollection`)?

···

On Sun, Nov 12, 2017 at 4:54 AM, Brent Royal-Gordon <brent@architechies.com> wrote:

On Nov 10, 2017, at 11:01 PM, Xiaodi Wu <xiaodi.wu@gmail.com> wrote: