David Berry
David Berry

Reputation: 41226

How to declare a function that returns an iterable

I have a function that is currently defined as:

public func mappingsWithElementId(elementId:String) -> [Mapping] {
    return _mappings.lazy.map({ $1 }).filter({ $0.elementId == elementId })
}

I would like to change it so that rather than return an array, it just returns a (lazy) object that can be iterated, i.e., a CollectionType<Mapping> that the caller can then use however is appropriate.

Now, I can use:

public func mappingsWithElementId(elementId:String) -> LazyFilterCollection<LazyMapCollection<[String:Mapping], Mapping>> {
    return _mappings.lazy.map({ $1 }).filter({ $0.elementId == elementId })
}

But that's way overly specific for what I'm attempting to do (which is just tell the caller that it's something that can be iterated to get Mappings. And as I cascade more functions of a similar nature it just gets uglier and uglier.

Is there a way that I can declare my function which simply promises to return something that can be iterated as a CollectionType<Mapping>?

Trying to use CollectionType<Mapping> yields:

Cannot specialize non-generic type 'CollectionType'

Trying to use CollectionType gives me the error that:

Protocol 'CollectionType' can only be used as a generic constraint because it has Self or associated type requirements

Upvotes: 1

Views: 87

Answers (1)

Rob Napier
Rob Napier

Reputation: 299355

This is what type erasers are for. In this case you're looking for AnyForwardCollection:

public func mappingsWithElementId(elementId:String) -> AnyForwardCollection<Mapping> {
    return AnyForwardCollection(_mappings.lazy.map({ $1 }).filter({ $0.elementId == elementId }))
}

There are a bunch of others. AnySequence, AnyRandomAccessCollection, etc. You can create your own if you like, as well. See A Little Respect for AnySequence for more on that.

Upvotes: 3

Related Questions