extension Collection {
var onlyElement: Element? {
if let element = self.first,
self.index(after: self.startIndex) == self.endIndex {
element
} else {
nil
}
}
}
if let item = items.onlyElement {
…
}
I think that reads better, in that specific case. It's more explicit and straightforward.
That said, for the situations where count is more than one, I see merit in pattern matching support, or destructing a la tuples. e.g.:
if let (first, second) = items {
…
}
P.S. I had to check the Collection documentation to confirm that count is not guaranteed to be O(1). Re. your method for efficiently checking if the collection has one element. Which reiterates the need for of a contains(atLeast: Int) method for Collection.
sure. but you would have to duplicate that extension in every module that requires it, to avoid running afoul the “don’t (publicly and generically) extend types you don’t own” principle.
IIRC it goes "don’t extend types you don’t own with protocols you don't own". The first part alone is fine as it is pretty much equivalent to having a standalone function:
func myFunction<C: Collection>(_ collection: C) -> C.Element? {
}
C# has a pair of functions like this via LINQ: in Swift they would be consuming func single() throws -> Element and consuming func singleOrDefault() -> Element?
I’m not very aware of this principle. I personally have Collection.only defined in a package I own and I use it all the time. I can imagine some possible arguments for the principle you mention, but can you tell me a bit about it? Do you have any link to discussion about it?
what if you start a second package, and that package also has a Collection.only extension? then anyone (including future you) who wants to depend on modules from both packages simultaneously will be unable to use either helper method.
Firstly, plan A would be to not define Collection.only in any other package - anywhere I need Collection.only I'll depend on the one package in which it is defined.
But worst comes to worst, the situation you describe is solvable:
Package C wants to depend on package A and package B, both of which define Collection.only. I can create a module named disambiguation-Collection-only inside of the C package and only import either A or B, then disambiguate using the following code:
import A
extension Collection {
public var onlyElement: Element? {
self.only
}
}
and then import disambiguation-Collection-only in the rest of the modules of my package where it's needed.
// file1.swift
import A
collection.only // ✅ uses A.collection.only
// file2.swift
import B
collection.only // ✅ uses B.collection.only
// file3.swift
import A
import B
collection.only // 🛑 ambiguous use of collection "only" (defined in both A and B)
// file4.swift
// no import A or B
collection.only // 🛑 collection "only" is defined in more than one module, specify the one you want
Oh, right - I’m so used to @_exported imports that I forgot that a separate module for the purpose of disambiguation wouldn’t even be necessary, a separate file would suffice.
I mean I'm not sure if it works like this or not today, it just feels it would be the best way to solve the issue raised by @taylorswift. Does it actually work like this today?
Which is a problem @taylorswift is talking about, no? Which onlyElement is used here? I'd prefer to have a compilation error in this case. Ditto when there is no explicit "import A" or "import B".
If "only" here is always A's and never B's - that's good.
I’d love to see this, but it would need to work with future destructuring and pattern matching of structured types (class, struct, dict). The syntax proposed previously resembled closure capture lists.