What are the differences between 'CaseIterable' protocol's allCases and AllCases? - swift

I am curious about the differences between 'CaseIterable' protocol's allCases and AllCases. According to Apple's document:
allCases : A collection of all values of this type. https://developer.apple.com/documentation/swift/caseiterable/2994869-allcases
AllCases : A type that can represent a collection of all values of this type. https://developer.apple.com/documentation/swift/caseiterable/2994868-allcases,
The most common usage when using 'CaseIterable' protocol seems to be allCases and I am aware of its actual usage in enum, but I can't find a solid example that explains the usage of AllCases. Any input will be appreciated.
Thank you.

First, go learn what associated types are.
Armed with that knowledge, you'll understand that AllCases just has to be a Collection of instances of a type—not specifically the Array of enumeration instances you'll generally experience it expressed as.
So, for a type with enumerable instances, whose order doesn't matter, you could use a Set, for example.
extension Bool: CaseIterable {
public static var allCases: Set<Self> { [true, false] }
}
extension Sequence where Element == Bool {
var containsBothBools: Bool { Bool.allCases.isSubset(of: self) }
}
[true].containsBothBools // false
[false].containsBothBools // false
[true, false, true, true, false, true].containsBothBools // true

Related

Inserting a unique value in the set based on value's property

I've created a struct with an "id" property:
struct SomeStruct: Hashable {
let id: String; // should be unique
let date: String;
let comment: String;
static func ==(lhs: SomeStruct, rhs: SomeStruct) -> Bool {
return lhs.id == rhs.id
}
}
I need to insert these structs in a set, but the set itself should decide whether the new member is unique or not based on its id, so:
someSet.insert(SomeStruct(id: "1", date: "22.09.2022", comment: "nothing here")) //inserted: true
someSet.insert(SomeStruct(id: "1", date: "05.12.1978", comment: "something here!")) //inserted: false, not unique id
That is why I implement the equality operator func in the struct and sometimes it works... but sometimes it doesn't and here I am, humbly asking for your help.
My implementation gives me weird results. The structs with the same id's can both be inserted or not, for example if I build my playground file once and new value gets inserted, next time I build it and the same value returns false.
I may have missed something, maybe I should implement custom hashValue property..?
Thanks in advance.
P.S. My job is to create a collection of these structs, where each struct has unique id. If you did it before and/or you think you know how to do it better, please let me know, I will be very glad to hear your ideas.
A solution was given in comments, which was to hash only on id instead of relying on the compiler generated implementation, which hashes on all the properties. That solution is a perfectly valid one for the stated problem, and may be ideal for your use case.
It does have one potential drawback: It means SomeStruct is only ever hashably-distinct based on id. That is the case that's presented, but we don't see the wider code base (nor should we). Is SomeStruct only ever used so that having its hash value based solely on its id is the right thing? It definitely could be, and probably is, since most things with a unique ID work that way, but it doesn't have to be, and I don't like making that assumption about code I can't see.
A more code-base agnostic and reusable approach is rather than tweaking the data's implementation to make a given collection behave the way you want, you can make a collection with that desired behavior for the data you have. There's more code involved in this approach, but it also gives more flexibility in how you can use the data.
The described behavior is that of a Dictionary keyed on the id, but the API of Set. There are some options. Here's one.
First make SomeStruct conform to Identifiable which is a standard Swift protocol. All that means is that it needs a Hashable id property, which you already have so adding that conformance is just:
extension SomeStruct: Identifiable { }
Though you could add Identifiable to the definition of SomeStruct instead. Either way works.
Then create a data structure that is keyed on id. This doesn't have to be complicated. Just leverage the existing thing that does most of what you need to implement it. In this case, that's Dictionary. So here's a minimal, but generic, IDSet that does that:
struct IDSet<T: Identifiable>
{
public typealias Element = T
internal typealias Storage = [Element.ID: Element]
private var storage = Storage()
public mutating func insert(_ value: Element) -> Bool
{
guard !storage.keys.contains(value.id) else { return false }
storage[value.id] = value
return true
}
}
Because IDSet is generic, you can make one for any kind of Identifiable thing. It also doesn't need for the whole element to be Hashable. It only needs its id to be Hashable. That gives you more flexibility in the kinds of elements you store in it.
Presumably you'd want to iterate over the elements, so you'd need to make it conform to Sequence. Again there's no need to get complicated in making an Iterator, because you can leverage Dictionary's Iterator:
extension IDSet: Sequence
{
public struct Iterator: IteratorProtocol
{
internal var iter: Storage.Iterator
public mutating func next() -> Element?
{
guard let (_, value) = iter.next() else { return nil }
return value
}
}
public func makeIterator() -> Iterator {
Iterator(iter: storage.makeIterator())
}
}
You probably want IDSet to conform to some other protocols too, but I think it's likely you can see how that would work.
To use it, it's much like Set, although insert returns a non-discardable Bool indicating whether the element was inserted. Let's say you want to test this behavior in XCTest using your example data:
var someSet = IDSet<SomeStruct>()
XCTAssertTrue(someSet.insert(SomeStruct(id: "1", date: "22.09.2022", comment: "nothing here")))
XCTAssertFalse(someSet.insert(SomeStruct(id: "1", date: "05.12.1978", comment: "something here!")))
And of course, because it conforms to Sequence you can iterate over it:
for s in someSet {
print("id: \(s.id), date: \(s.date), comment: \"\(s.comment)\"")
}
Or use various other Sequence methods:
let comments = someSet.map { $0.comment }
Set elements are Hashable
Hashing a value means feeding its essential components into a hash function, represented by the Hasher type. Essential components are those that contribute to the type’s implementation of Equatable. Two instances that are equal must feed the same values to Hasher in hash(into:), in the same order.
I suggest adding:
struct SomeStruct: Hashable {
let id: String;
let date: String;
let comment: String;
static func ==(lhs: SomeStruct, rhs: SomeStruct) -> Bool {
return lhs.id == rhs.id
}
public func hash(into hasher: inout Hasher) {
// feed the only property that contribute to Equatable implementation
hasher.combine(id)
}
}

Why is generic specialization lost inside a generic function

When I create a computed property that depends on a generic type, the specific implementation is "lost" when the instance is passed in a generic function.
For example, I added the isBool on Array that returns true if Array.Element is Bool:
extension Array {
var isBool: Bool {
false
}
}
extension Array where Element == Bool {
var isBool: Bool {
true
}
}
Using it directly on the instance works fine
let boolArray: [Bool] = [true, false]
let intArray: [Int] = [1, 0]
boolArray.isBool // true
intArray.isBool // false
But inside a generic function it always uses the non specialized implementation:
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
isBool(boolArray) // false, instead of true
isBool(intArray) // false
This is not a real use case so I don't really need a way to "fix" this, but I would like to understand why it behave like that.
Specialization is not a replacement for inheritance. It should be used to improve performance, not change behavior.
For example, distance(from:to:) is usually O(k), where k is the distance. For RandomAccessCollection it can be performed in O(1) due to a specialization. But the result is the same either way.
Specialization is done at compile-time based on the information the compiler has. In your example, the compiler can see that boolArray is a [Bool], and so it uses the specialized extension. But inside of isBool, all that the compiler knows is that array is an Array. It doesn't know when compiling the function what kind of Array will be passed. So it picks the more general version to cover all cases.
(The compiler may create multiple versions of isBool in the binary for optimization purposes, but luckily I haven't found any situations where this impacts what extensions or overloads are called. Even if it actually creates an inlined, Bool-specific version of isBool, it will still use the more general Array extension. That's a good thing.)
Leaving your extensions in place, the following would do what you expect (though I don't encourage this):
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
func isBool(_ array: [Bool]) -> Bool {
array.isBool
}
Now isBool is overloaded and the most specific one will be selected. Within the context of the second version, array is known to be [Bool], and so the more specialized extension will be selected.
Even though the above works, I would strongly recommend against using specialized extensions or ambiguous overloads that change behavior. It is fragile and confusing. If isBool() is called in the context of another generic method where Element is not known, it again may not work as you expect.
Since you want to base this on the runtime types, IMO you should query the type at runtime using is. That gets rid of all the ambiguity. For example:
extension Array {
var isBool: Bool { Element.self is Bool.Type }
}
func isBool<Element>(_ array: [Element]) -> Bool {
array.isBool
}
You can make this much more flexible and powerful by adding a protocol:
protocol BoolLike {}
extension Array {
var isBool: Bool { Element.self is BoolLike.Type }
}
Now, any types you want to get "bool-like" behavior just need to conform:
extension Bool: BoolLike {}
This allows you all the flexibility of your extensions (i.e. the isBool code doesn't need to know all the types), while ensuring the behavior is applied based on runtime types rather than compile-time types.
Just in case it comes up, remember that protocols do not conform to themselves. So [BoolLike] would return isBool == false. The same is true for an extension with where Element: BoolLike. If you need that kind of thing to work, you need to deal with it explicitly.
extension Array {
var isBool: Bool {
Element.self is BoolLike.Type || Element.self == BoolLike.self
}
}

Does Swift have short-circuiting higher-order functions like Any or All?

I'm aware of Swift's higher-order functions like Map, Filter, Reduce and FlatMap, but I'm not aware of any like 'All' or 'Any' which return a boolean that short-circuit on a positive test while enumerating the results.
For instance, consider you having a collection of 10,000 objects, each with a property called isFulfilled and you want to see if any in that collection have isFulfilled set to false. In C#, you could use myObjects.Any(obj -> !obj.isFulfilled) and when that condition was hit, it would short-circuit the rest of the enumeration and immediately return true.
Is there any such thing in Swift?
Sequence (and in particular Collection and Array) has a (short-circuiting) contains(where:) method taking a boolean predicate as argument. For example,
if array.contains(where: { $0 % 2 == 0 })
checks if the array contains any even number.
There is no "all" method, but you can use contains() as well
by negating both the predicate and the result. For example,
if !array.contains(where: { $0 % 2 != 0 })
checks if all numbers in the array are even. Of course you can define a custom extension method:
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) -> Bool) -> Bool {
return !contains(where: { !predicate($0) } )
}
}
If you want to allow "throwing" predicates in the same way as the
contains method then it would be defined as
extension Sequence {
func allSatisfy(_ predicate: (Iterator.Element) throws -> Bool) rethrows -> Bool {
return try !contains(where: { try !predicate($0) } )
}
}
Update: As James Shapiro correctly noticed, an allSatisfy method has been added to the Sequence type in Swift 4.2 (currently in beta), see
SE-0027 Add an allSatisfy algorithm to Sequence
(Requires a recent 4.2 developer snapshot.)
One other thing that you can do in Swift that is similar to "short circuiting" in this case is to use the lazy property of a collection, which would change your implementation to something like this:
myObjects.lazy.filter({ !$0.isFulfilled }).first != nil
It's not exactly the same thing you're asking for, but might help provide another option when dealing with these higher-order functions. You can read more about lazy in Apple's docs. As of this edit the docs contain the following:
var lazy: LazyCollection> A view onto this collection
that provides lazy implementations of normally eager operations, such
as map and filter.
var lazy: LazySequence> A sequence containing the same
elements as this sequence, but on which some operations, such as map
and filter, are implemented lazily.
If you had all the objects in that array, they should conform to some protocol, which implements the variable isFulfilled... as you can see, you could make these objects confrom to (let's call it fulFilled protocol)... Now you can cast that array into type [FulfilledItem]... Now you can continue as usually
I am pasting code here for your better understanding:
You see, you cannot extend Any or AnyObject, because AnyObject is protocol and cannot be extended (intended by Apple I guess), but you can ,,sublass" the protocol or as you like to call it professionally - Make protocol inheriting from AnyObject...
protocol FulfilledItem: AnyObject{
var isFulfilled: Bool {get set}
}
class itemWithTrueValue: FulfilledItem{
var isFulfilled: Bool = true
}
class itemWithFalseValue: FulfilledItem{
var isFulfilled: Bool = false
}
var arrayOfFulFilled: [FulfilledItem] = [itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue(),itemWithFalseValue()]
let boolValue = arrayOfFulFilled.contains(where: {
$0.isFulfilled == false
})
Now we've got ourselves a pretty nice looking custom protocol inheriting all Any properties + our beautiful isFulfilled property, which we will handle now as usually...
According to apple docs:
https://developer.apple.com/library/content/documentation/Swift/Conceptual/Swift_Programming_Language/TypeCasting.html#//apple_ref/doc/uid/TP40014097-CH22-ID342
AnyObject is only for reference types (classes), Any is for both value and reference types, so I guess it is prefered to inherit AnyObject...
Now you cast instead AnyObject into Array the protocol Item FulfilledItem and you will have beautiful solution (don't forget every item to conform to that protocol and set the value...)
Wish happy coding :)

Using diff in an array of objects that conform to a protocol

I'm experimenting with using Composition instead of Inheritance and I wanted to use diff on an array of objects that comply with a given protocol.
To do so, I implemented a protocol and made it comply with Equatable:
// Playground - noun: a place where people can play
import XCPlayground
import Foundation
protocol Field:Equatable {
var content: String { get }
}
func ==<T: Field>(lhs: T, rhs: T) -> Bool {
return lhs.content == rhs.content
}
func ==<T: Field, U: Field>(lhs: T, rhs: U) -> Bool {
return lhs.content == rhs.content
}
struct First:Field {
let content:String
}
struct Second:Field {
let content:String
}
let items:[Field] = [First(content: "abc"), Second(content: "cxz")] // 💥 boom
But I've soon discovered that:
error: protocol 'Field' can only be used as a generic constraint because it has Self or associated type requirements
I understand why since Swift is a type-safe language that needs to be able to know the concrete type of these objects at anytime.
After tinkering around, I ended up removing Equatable from the protocol and overloading the == operator:
// Playground - noun: a place where people can play
import XCPlayground
import Foundation
protocol Field {
var content: String { get }
}
func ==(lhs: Field, rhs: Field) -> Bool {
return lhs.content == rhs.content
}
func ==(lhs: [Field], rhs: [Field]) -> Bool {
return (lhs.count == rhs.count) && (zip(lhs, rhs).map(==).reduce(true, { $0 && $1 })) // naive, but let's go with it for the sake of the argument
}
struct First:Field {
let content:String
}
struct Second:Field {
let content:String
}
// Requirement #1: direct object comparison
print(First(content: "abc") == First(content: "abc")) // true
print(First(content: "abc") == Second(content: "abc")) // false
// Requirement #2: being able to diff an array of objects complying with the Field protocol
let array1:[Field] = [First(content: "abc"), Second(content: "abc")]
let array2:[Field] = [Second(content: "abc")]
print(array1 == array2) // false
let outcome = array1.diff(array2) // 💥 boom
error: value of type '[Field]' has no member 'diff'
From here on, I'm a bit lost to be honest. I read some great posts about type erasure but even the provided examples suffered from the same issue (which I assume is the lack of conformance to Equatable).
Am I right? And if so, how can this be done?
UPDATE:
I had to stop this experiment for a while and totally forgot about a dependency, sorry! Diff is a method provided by SwiftLCS, an implementation of the longest common subsequence (LCS) algorithm.
TL;DR:
The Field protocol needs to comply with Equatable but so far I have not been able to do this. I need to be able to create an array of objects that comply to this protocol (see the error in the first code block).
Thanks again
The problem comes from a combination of the meaning of the Equatable protocol and Swift’s support for type overloaded functions.
Let’s take a look at the Equatable protocol:
protocol Equatable
{
static func ==(Self, Self) -> Bool
}
What does this mean? Well it’s important to understand what “equatable” actually means in the context of Swift. “Equatable” is a trait of a structure or class that make it so that any instance of that structure or class can be compared for equality with any other instance of that structure or class. It says nothing about comparing it for equality with an instance of a different class or structure.
Think about it. Int and String are both types that are Equatable. 13 == 13 and "meredith" == "meredith". But does 13 == "meredith"?
The Equatable protocol only cares about when both things to be compared are of the same type. It says nothing about what happens when the two things are of different types. That’s why both arguments in the definition of ==(::) are of type Self.
Let’s look at what happened in your example.
protocol Field:Equatable
{
var content:String { get }
}
func ==<T:Field>(lhs:T, rhs:T) -> Bool
{
return lhs.content == rhs.content
}
func ==<T:Field, U:Field>(lhs:T, rhs:U) -> Bool
{
return lhs.content == rhs.content
}
You provided two overloads for the == operator. But only the first one has to do with Equatable conformance. The second overload is the one that gets applied when you do
First(content: "abc") == Second(content: "abc")
which has nothing to do with the Equatable protocol.
Here’s a point of confusion. Equability across instances of the same type is a lower requirement than equability across instances of different types when we’re talking about individually bound instances of types you want to test for equality. (Since we can assume both things being tested are of the same type.)
However, when we make an array of things that conform to Equatable, this is a higher requirement than making an array of things that can be tested for equality, since what you are saying is that every item in the array can be compared as if they were both of the same type. But since your structs are of different types, you can’t guarantee this, and so the code fails to compile.
Here’s another way to think of it.
Protocols without associated type requirements, and protocols with associated type requirements are really two different animals. Protocols without Self basically look and behave like types. Protocols with Self are traits that types themselves conform to. In essence, they go “up a level”, like a type of type. (Related in concept to metatypes.)
That’s why it makes no sense to write something like this:
let array:[Equatable] = [5, "a", false]
You can write this:
let array:[Int] = [5, 6, 7]
or this:
let array:[String] = ["a", "b", "c"]
or this:
let array:[Bool] = [false, true, false]
Because Int, String, and Bool are types. Equatable isn’t a type, it’s a type of a type.
It would make “sense” to write something like this…
let array:[Equatable] = [Int.self, String.self, Bool.self]
though this is really stretching the bounds of type-safe programming and so Swift doesn’t allow this. You’d need a fully flexible metatyping system like Python’s to express an idea like that.
So how do we solve your problem? Well, first of all realize that the only reason it makes sense to apply SwiftLCS on your array is because, at some level, all of your array elements can be reduced to an array of keys that are all of the same Equatable type. In this case, it’s String, since you can get an array keys:[String] by doing [Field](...).map{ $0.content }. Perhaps if we redesigned SwiftLCS, this would make a better interface for it.
However, since we can only compare our array of Fields directly, we need to make sure they can all be upcast to the same type, and the way to do that is with inheritance.
class Field:Equatable
{
let content:String
static func == (lhs:Field, rhs:Field) -> Bool
{
return lhs.content == rhs.content
}
init(_ content:String)
{
self.content = content
}
}
class First:Field
{
init(content:String)
{
super.init(content)
}
}
class Second:Field
{
init(content:String)
{
super.init(content)
}
}
let items:[Field] = [First(content: "abc"), Second(content: "cxz")]
The array then upcasts them all to type Field which is Equatable.
By the way, ironically, the “protocol-oriented” solution to this problem actually still involves inheritance. The SwiftLCS API would provide a protocol like
protocol LCSElement
{
associatedtype Key:Equatable
var key:Key { get }
}
We would specialize it with a superclass
class Field:LCSElement
{
let key:String // <- this is what specializes Key to a concrete type
static func == (lhs:Field, rhs:Field) -> Bool
{
return lhs.key == rhs.key
}
init(_ key:String)
{
self.key = key
}
}
and the library would use it as
func LCS<T: LCSElement>(array:[T])
{
array[0].key == array[1].key
...
}
Protocols and Inheritance are not opposites or substitutes for one another. They complement each other.
I know this is probably now what you want but the only way I know how to make it work is to introduce additional wrapper class:
struct FieldEquatableWrapper: Equatable {
let wrapped: Field
public static func ==(lhs: FieldEquatableWrapper, rhs: FieldEquatableWrapper) -> Bool {
return lhs.wrapped.content == rhs.wrapped.content
}
public static func diff(_ coll: [Field], _ otherCollection: [Field]) -> Diff<Int> {
let w1 = coll.map({ FieldEquatableWrapper(wrapped: $0) })
let w2 = otherCollection.map({ FieldEquatableWrapper(wrapped: $0) })
return w1.diff(w2)
}
}
and then you can do
let outcome = FieldEquatableWrapper.diff(array1, array2)
I don't think you can make Field to conform to Equatable at all as it is designed to be "type-safe" using Self pseudo-class. And this is one reason for the wrapper class. Unfortunately there seems to be one more issue that I don't know how to fix: I can't put this "wrapped" diff into Collection or Array extension and still make it support heterogenous [Field] array without compilation error:
using 'Field' as a concrete type conforming to protocol 'Field' is not supported
If anyone knows a better solution, I'm interested as well.
P.S.
In the question you mention that
print(First(content: "abc") == Second(content: "abc")) // false
but I expect that to be true given the way you defined your == operator

Define a protocol that holds Collection as a property

I want to define a protocol that defines a variable "sequence" that is of type "Collection". I want that, because i have several conforming types, that will all hold an array of different types. Example:
protocol BioSequence {
associatedtype T
var sequence: Collection { get }
// Will also implement conformance to Collection and redirect all Collection functions to the property "sequence". This is because my types that conform to BioSequence are just wrappers for an array of Nucleotide or AminoAcid with some extra functionality
}
struct DNASequence: BioSequence {
// Will hold "sequence" of type [Nucleotide]
}
struct AminoSequence: BioSequence {
// Will hold "sequence" of type [AminoAcid]
}
Why do i want this? Because i need to implement the conformance to "Collection" only once in BioSequence and all conforming type inherit it automatically. Plus i can freely add extra functionality on the conforming types.
Now, when i try this like the code above, the compiler says: "Protocol Collection can only be used as a generic constraint". Yes, i googled what this error means, but how can i actually fix it to make my code work, like i want. Or is it not even possible to do what i want?
Thank you.
You can easily achieve this by using an associatedtype in your protocol, which can be constrained to Collection, allowing conforming types to satisfy the requirement with a concrete type when they adopt the protocol.
For example:
protocol CollectionWrapper : Collection {
associatedtype Base : Collection
var base: Base { get }
}
extension CollectionWrapper {
var startIndex: Base.Index {
return base.startIndex
}
var endIndex: Base.Index {
return base.endIndex
}
func index(after i: Base.Index) -> Base.Index {
return base.index(after: i)
}
subscript(index: Base.Index) -> Base.Iterator.Element {
return base[index]
}
// Note that Collection has default implementations for the rest of the
// requirements. You may want to explicitly implement them and forward them to
// the base collection though, as it's possible the base collection implements
// them in a more efficient manner (e.g being non random access and having
// a stored count).
}
// S adopts CollectionWrapper and satisfies the 'Base' associatedtype with [String].
struct S: CollectionWrapper {
var base: [String]
}
let s = S(base: ["foo", "bar", "baz"])
print(s[1]) // "bar"
Regarding your comment:
If I want to use this like that: let a: CollectionWrapper = S() [...] this leaves me with "Protocol can only be used as a generic constraint" again.
The problem is that you cannot currently talk in terms of a protocol with associated type requirements, as the types which are used to satisfy those requirements are unknown to the compiler (this isn't a technical limitation though). You can solve this by using Swift's AnyCollection type eraser to wrap an arbitrary Collection with a given element type.
For example:
let a = AnyCollection(S(base: ["foo", "bar", "baz"]))
If you need to work with additional protocol requirements from CollectionWrapper, you'll have to implement your own type eraser to do so. See Rob's answer here for an idea of how to go about this.