Any particular reason that Bool doesn't conform to CaseIterable?

I don't think there's any computer science type theory reason, but that we just simply forgot. (It's actually a struct, not an enum.)

Added as SR-13632 ("Have Bool conform to CaseIterable").

3 Likes

Sounds reasonable semantically. Would need proposal. What is a practical use case for it though?

The same for any other CaseIterable-conforming type, to make loops over all of its values. We can make a two-element array with a map. And not conforming is viral on any enumeration type that wants to use Bool as part of a payload.

2 Likes

You're describing the API of CaseIterable. But what is an example of a practical use case for that, for Bool?

1 Like

There might be generic algorithms or data-structures which depend on CaseIterable (after all, it exists as a protocol because it is a useful abstraction). If you wanted to use that code with Bool, you’d need to make a type you don’t own conform to a protocol you don’t own, which is a big no-no.

So I agree that it is reasonable, even without concrete use-cases (just inferring that it is useful because CaseIterable is), and only the standard library can properly enable it.

1 Like

Sure, if we posit the existence of these algorithms and we assume they would make sense to use with Bool; do we have real-world examples of such? Phrased differently, are there use cases where this protocol is a useful abstraction that would equally be useful for Bool?

Personally I’ve only found limited use for CaseIterable, but I know others have found it useful.

I guess what I’m saying is that, since we discourage these kinds of retroactive conformances, every conformance we don’t add between standard library types and protocols is almost a conscious design decision. In other words, stdlib types should conform to as many stdlib protocols as they can, even if we can’t picture a specific use.

2 Likes

That would be entirely counter to the principles behind evolving the design of the standard library. If a feature is not demonstrably useful, and we can't even picture a specific use, it absolutely should not be added (or even considered). Each conformance adds to the design complexity of the standard library. We would not go around conforming types to protocols just because we can.

Without replying on whether or not we should do this, we still don't have any syntax or compiler support to add conformances to stdlib types post ABI. See: Backwards-deployable Conformances. So even if a proposal were to be born, evaluated, and accepted, it would forever be blocked by this. Not trying to be a debbie downer, just trying to set expectations here.

5 Likes

There appear to be libraries which build form UIs for types with CaseIterable properties. That’s a use-case that I think could apply to Bool.

This is a recipe for bad design IMHO. Bool should ne be represented in UI like a CaseIterable. It should use a check box or a switch, and CaseIterable should use a dropdown list or something like that.

It's the only scalar type provided by the Standard Library that doesn't currently provide any form of automated traversal. (The other scalar types are the default numeric types, and as such all conform to Strideable.) It would be even less appropriate to make Bool conform to Comparable (let alone Strideable) to use with ranges, so CaseIterable is the only other way to do it.

The inspiration came from a test suite I'm writing. I originally made separate testing statements for each enumeration case. Then I remembered about CaseIterable and made my type conform. So I could redo the tests as a loop:

let expected = [ /*...*/ ]
let expectedResults = Dictionary(uniqueKeysAndValues: zip(MyEnum.allCases, expected))
for c in MyEnum.allCases {
    XCTAssertEqual(myFunction(c), expectedResults[c], "\(c)")
}

I realized I may want to test function results against a Bool argument someday, and checked if Bool supports CaseIterable. We have these higher-order functions, but can't use them with Bool without explicitly writing a "[false, true]" or "[myFunc(false), myFunc(true)]".

2 Likes

Depends on the platform - what you said is what Apple recommend for their most popular platforms, but is not necessarily a universal rule. Some Interfaxes might not even be visual - you might generate an audio interface, or one that is presented on some special assistive device.

The more general point is - CaseIterable is useful for generating interfaces based on the possible values that a type can have, and Bool is able to provide that information, which is the only thing that generic code cares about. Whether or not that code wishes to special-case Bool is their own decision.

3 Likes

I didn't think about Apple OS in particular. This is true for the web (HTML), for Android, for Java (Swing, JavaFX, …), and for any other toolkit I had to use.

And even for non-graphical interfaces, I don't think presenting a Bool like any choice list is the best way to represent them.

Bool have a very well defined and well-known semantic that you just ignore when using them like any CaseIterable.

There may be some rare case where it does not matter, but I don't think they are common enough to make Bool conform to CaseIterable.

It doesn’t make sense because one of the orders is as good as the other.

Are there any Types that have CaseIterabe conformance built-in? I'm not aware of any. I would expect the reasons it shouldn't be added to Bool is the same reason it shouldn't automatically be added to every enum There's no objective order that can be applied in all situations, and it's very easy for users that need the functionality to opt-in.

I want to automatically traverse every value, not necessarily want the publication order to be part of any semantic. Yet another reason to have a Sequence-with-the-publication-order-is-part-of-the-type's-semantics-"requirement"-ripped-out protocol. (It should be a base protocol to Sequence, but that brings ABI difficulties.)

1 Like