> On Nov 14, 2017, at 5:21 PM, Xiaodi Wu <xiaodi...@gmail.com> wrote:
> 
> 1. It must be possible to easily access the count of values, and to access 
> any particular value using contiguous `Int` indices. This could be achieved 
> either by directly accessing elements in the list of values through an Int 
> subscript, or by constructing an Array from the list of values.
> 
> 2. It must be possible to control the order of values in the list of values, 
> either by using source order or through some other simple, straightforward 
> mechanism.
>  
> OK, first of all, nowhere in the proposal text are these requirements stated 
> as part of the use case. You're free to put forward new use cases, but here I 
> am trying to design the most elegant way to fulfill a stated need and you're 
> telling me that it's something other than what's written.

Honestly, re-reading the proposal, it never cites a fully-formed use case. 
Instead, it cites several blog posts, Stack Overflow questions, and small code 
samples without digging in to the underlying reasons why developers are doing 
what they're doing. Most of the people discussing it so far seem to have had a 
tacit understanding that we wanted roughly Array-like access, but we haven't 
explicitly dug into which properties of an Array are important.

(If anyone involved feels like they had a different understanding of the use 
case, please speak up.)

I think this is a place where the proposal can be improved, and I'm willing to 
do some writing to improve it.

> You say that:
> 
>>  Essentially all other uses for enumeration of enum cases can be trivially 
>> recreated based on just that.
> 
> 
> But with this use case in mind, we can see that it is "trivial" in the sense 
> that the annoying boilerplate you need to bridge the significant impedance 
> mismatch is easy to come up with. Yes, you could construct an array using the 
> magic `for` loop, but that would be a serious pain. (And there would be no 
> ergonomic, mistake-resistant way to hide that pain behind a 
> function/initializer call, because there's no way to say that a parameter 
> must be a metatype for an enum.) What you really want is a way to access or 
> construct an `Array` or array-like type containing the type's values.
> 
> You cannot truly believe that
> 
> ```
> var cases = [BugStatus]()
> for c in BugStatus.self { cases.append(c) }
> ```
> 
> is "serious pain." Yes, part of being an incomplete implementation is that it 
> lacks the ergonomics of a fleshed-out conformance to `Collection`. But 
> "serious pain"?

Yes, I'll stand by "serious pain". This is fundamentally a convenience feature, 
so it needs to actually *be* convenient—more convenient than writing out the 
enum cases in an array literal. Forcing users to write imperative-style code 
that can't be encapsulated is not convenient.

> The point here is that even a minimal step towards what we agree is the ideal 
> design would make _possible_ what today is _impossible_: namely, future-proof 
> enumeration of all the cases of an enum type without associated values.

We can take a minimal step towards having the feature…or we can just have the 
feature.

> *Actually* conforming the metatype to `Sequence` or `Collection` would be a 
> different story. There, you could construct `Array`s or access elements using 
> ordinary APIs and type system features. And you could write generic 
> algorithms which used the set of all types: they would require conformance to 
> `Sequence` or `Collection`, and users would specify `Foo.Type` as the generic 
> parameter.
> 
> Indeed. The point here is that we don't need a name for this protocol. You'd 
> be able to write useful generic algorithms by using functions such as `map` 
> on `T.self` with intuitive constraints such as `T where T.Type : Collection`. 
> Isn't that a sublime way of expressing exactly what we mean? 

It is! As I said, I love the idea of conforming the metatype to 
`Collection`—it's very elegant. But the only advantage I can identify over this 
proposal is a slight gain in elegance, while its *disadvantages*—requiring 
several nontrivial enhancements to the language, and therefore deferring large 
amounts of very desirable functionality to an unspecified future release—are 
significant.

Basically, I don't think it's worth waiting for the "sublime way".

(There's also the disadvantage that the meaning of `Foo.self[i]` is not 
immediately obvious in the way `Foo.allValues[i]` is. As it is, I'm not totally 
convinced that `ValueEnumerable` is an obvious enough name; `Foo.self` would be 
much more problematic in that sense.)

(And there's the opt-in question. Public types may not *want* to participate in 
this feature, but you seem to suggest they should have to.)

> But I suspect that would require deeper compiler changes than we can be 
> certain to get in Swift 5 or really at any specific point on the roadmap, and 
> I don't think we should delay this feature indefinitely to get a design whose 
> only real benefit is elegance.
> 
> We may (almost certainly) need more time to realize the full design. But we 
> don't need much to take the first steps towards it, which--as I write 
> above--would already make possible the currently impossible. It seems you'd 
> rather ship a complete but inelegant design forever than an incomplete but 
> useful part of an elegant design now. I wouldn't make that trade-off.


This is a feature people have wanted—asked for constantly—since Swift was 
released. SR-30 is the oldest bug labeled "LanguageFeatureRequest" in the 
Swift.org bug tracker. We've had several different threads, posted by several 
different people, independently proposing it. Outside the evolution process, 
questions and answers about how to do this (and related questions, like "how do 
I get the number of cases?", which is usually a backdoor version of it) are 
extremely common.

Apple deferred it beyond Swift 2, and Swift open source deferred it beyond 
Swift 3 and 4, in part because we saw that future associated type features and 
finalized type metadata formats would make the implementation significantly 
better if we waited. The type features are now here, and the metadata format 
will be frozen in the next release. We have everything we need right now to 
make a very good version of this feature. You propose deferring it again, not 
because the functionality would be appreciably improved by the delay, but 
because it could be done more cleverly.

So let me turn the question around: Why *should* we wait? What appreciable 
advantages, *besides* elegance, do conforming the metatype to `Collection` 
offer over a static constant? If someone buttonholes you at a conference and 
asks, "Why did you choose a magic `for` loop, instead of just giving us an 
array of cases?", what is your answer, and is it one that will satisfy them?

Personally, I don't think I could give the answer "We thought of a design that 
offered no additional functionality, but was much cooler" with a straight face.

-- 
Brent Royal-Gordon
Architechies

_______________________________________________
swift-evolution mailing list
swift-evolution@swift.org
https://lists.swift.org/mailman/listinfo/swift-evolution

Reply via email to