A long time ago, I think Swift 3, I tried writing a system where a predicate-bearing algorithm can handle both throwing and non-throwing predicates without writing the meat of the algorithm twice. I couldn't get past that IteratorProtocol.next()
is never throwing, and couldn't handle how to propagate the error, let alone how to conditionally propagate the error.
I just tried again, this time hoping Swift 5's Result
can help. I got to:
extension Sequence {
public func presortedSubtract<T: Sequence, U: RangeReplaceableCollection>(sortedFilterElements: T, storingAs: U.Type, by areInIncreasingOrder: (Element, Element) throws -> Bool) throws -> U where T.Element == Element, U.Element == Element {
return try withoutActuallyEscaping(areInIncreasingOrder) { predicate in
return try U(IteratorSequence(FullSetSubtractionImplementationIterator(makeIterator(), filter: sortedFilterElements.makeIterator(), by: predicate)).lazy.map { try $0.get() })
}
}
public func presortedSubtract<T: Sequence, U: RangeReplaceableCollection>(sortedFilterElements: T, storingAs: U.Type, by areInIncreasingOrder: (Element, Element) -> Bool) -> U where T.Element == Element, U.Element == Element {
return withoutActuallyEscaping(areInIncreasingOrder) { predicate in
return U(IteratorSequence(FullSetSubtractionImplementationIterator(makeIterator(), filter: sortedFilterElements.makeIterator(), by: predicate)).lazy.map { try! $0.get() })
}
}
}
Where FullSetSubtractionImplementationIterator
(based off this post of mine) vends Result<Element, Error>
instead of Element
. These functions originally weren't public
; I tried to unify them to a single method based off rethrows
:
extension Sequence {
func presortedSubtractToo<T: Sequence, U: RangeReplaceableCollection>(sortedFilterElements: T, storingAs: U.Type, by areInIncreasingOrder: (Element, Element) throws -> Bool) rethrows -> U where T.Element == Element, U.Element == Element {
return try presortedSubtract(sortedFilterElements: sortedFilterElements, storingAs: U.self, by: areInIncreasingOrder)
}
}
I was hoping the compiler will look at areInIncreasingOrder
and choose the appropriate overload of presortedSubtract
based on the predicate's throwing status. There was an error on the "p" of the return
line with "Call can throw, but the error is not handled; a function declared 'rethrows' may only throw if its parameter does
," which seems slightly contradictory. (The first part assumes it's throwing, but second if it's non-throwing.)
BTW, removing the "try
" gives "Call can throw, but it is not marked with 'try' and the error is not handled; a function declared 'rethrows' may only throw if its parameter does
."
Is there some way to do this now that I missed, or do I have to keep two overloads? At least I can keep the algorithm in a single iterator type, and branch on "try $0.get()
" vs. "try! $0.get()
" in the corresponding functions.