I often find use for treating an empty string, or generally an empty collection, as nil.
One use case is a guard chain like:
guard
let inputToCollection = optionalValue(),
let collection = getCollection(), // Not valid, as it's not optional
let finalValue = valueFromCollection(collection)
{
// do stuff
}
I would like to propose this addition to the Collection protocol:
public extension Collection {
var nonEmpty: Self? { return isEmpty ? nil : self }
}
guard
let inputToCollection = optionalValue(),
let collection = getCollection().nonEmpty,
let finalValue = valueFromCollection(collection)
{
// do stuff
}
If also works for strings:
let value = getString().nonEmpty.map({ useNonEmptyString($0) }) ?? fallback
Your guard statement examples are a little odd, because they're missing the else, and read more like if statements (i.e. // do stuff is the important work, rather than an early bail-out).
So assuming you do want guard because you're bailing, the code could look something like:
guard let inputToCollection = optionalValue() else { return }
let collection = getCollection()
guard !collection.isEmpty else { return }
let finalValue = valueFromCollection(collection)
// do stuff
It's not clear to me why being able to combine those two guards in a single compound statement is a win. Breaking the statements out seems clearer, at least to me.
Perhaps if the error handling were more complex than a simple return (say, logging then throwing) it might help avoid repeating yourself in the else clauses. But then, if these are true errors I suspect you'd want to log different things depending on which case failed.
Collection.nonEmpty would still make it easier, and more readable, to make expressions where only non-empty collections (especially strings) should be considered.
+1 since I've been using this pattern since ObjC, and it‘s even nicer in Swift. However the name seems bad to me. Not that I have a better name (I call mine chuzzle).
I think if this were to be in the stdlib it should reference optionality or nill-ness is some manner. or perhaps compacted() would fit? Since we now have the related compactMap.
Edit: well compacted() suggests it might remove nils in the middle so… no. But I think the name with adjustment has legs.
I like nonEmpty because it clearly states that we want a non-empty collection. And some day this could even return a NonEmptyCollection of some sort with a compile time guarantee of non-emptiness.
It also works well with my other suggestion of isNonEmpty ;-)
My examples may be bad, but I do not consider using Functional Programming a fringe example To me Collection.nonEmpty enables writing clear and concise expressions that are very easy to reason about.