Is it OK if the lazy version slightly differs in one parameter?

lazy

(Daryle Walker) #1

The eager version:

extension Sequence {

    public func allMatches<Pattern: Collection, Result: RangeReplaceableCollection>(for pattern: Pattern, allowingOverlap: Bool, storingAs: Result.Type, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> Result where Result.Element: RangeReplaceableCollection, Result.Element.Element == Element

}

You enter the type of the collection-of-collections. This implicitly determines the inner collection type.

The lazy version:

extension LazySequenceProtocol {

    public func allMatches<Pattern: Collection, Result: RangeReplaceableCollection>(for pattern: Pattern, allowingOverlap: Bool, storingEachAs: Result.Type, by areEquivalent: @escaping (Element, Pattern.Element) -> Bool) -> LazyMatchSequence<Elements, Result, Pattern> where Result.Element == Element

}

Since there is no outer collection, the type parameter only specifies the "inner" collection type. Note the parameter label is different ("storingAs" vs. "storingEachAs"), which should hopefully clue the user in. Is this OK?


(Ben Cohen) #2

To save you some time, which will probably circumvent the question: I don't think this is a practice I'd recommend. It's not clear this level of complexity is desirable for these functions. Returning [Element] is sufficient.

I'd also suggest that this isn't a method that belongs on Sequence in the first place. This kind of searching is really only applicable to collections, which can return slices representing the found sequences.


(Ben Cohen) #3

To the answer more directly: yes it's fine if justified. For example, lazy.map's closure argument cannot throw.


(Daryle Walker) #4

My current solution is to add the missing overload, going from:

extension Sequence {

    public func allMatches<Pattern: Collection, Result: RangeReplaceableCollection>(for pattern: Pattern, allowingOverlap: Bool, storingAs: Result.Type, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> Result where Result.Element: RangeReplaceableCollection, Result.Element.Element == Element

    public func allMatches<Pattern: Collection>(for pattern: Pattern, allowingOverlap: Bool, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> [[Element]] {
        return try allMatches(for: pattern, allowingOverlap: allowingOverlap, storingAs: Array<Array<Element>>.self, by: areEquivalent)
    }

}

to:

extension Sequence {

    public func allMatches<Pattern: Collection, Result: RangeReplaceableCollection>(for pattern: Pattern, allowingOverlap: Bool, storingAs: Result.Type, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> Result where Result.Element: RangeReplaceableCollection, Result.Element.Element == Element

    public func allMatches<Pattern: Collection, Result: RangeReplaceableCollection>(for pattern: Pattern, allowingOverlap: Bool, storingEachAs: Result.Type, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> [Result] where Result.Element == Element {
        return try allMatches(for: pattern, allowingOverlap: allowingOverlap, storingAs: Array<Result>.self, by: areEquivalent)
    }

    public func allMatches<Pattern: Collection>(for pattern: Pattern, allowingOverlap: Bool, by areEquivalent: (Element, Pattern.Element) throws -> Bool) rethrows -> [[Element]] {
        return try allMatches(for: pattern, allowingOverlap: allowingOverlap, storingEachAs: Array.self, by: areEquivalent)
    }

}

(Daryle Walker) #5

I have separate functions for Collection, and I'm about to work on a lazy version now.


(Daryle Walker) #6

I put all the combinations in the latest update to my Gist, in the new "MultipleSearch.swift" file.