This is a good question. You have to balance two concerns:
- (1) try to keep your API general, so you can change the implementation later
- (2) give the caller some useful operations to perform on the collection
Where (1) asks you to be as little specific about the type (e.g. Iterable over Seq), and (2) asks you the opposite.
Even if the return type is just Iterable, you can still return let’s say a Vector, so if the caller wishes to gain extra power, it can just call .toSeq or .toIndexedSeq on it, and that operation is cheap for a Vector.
As a measure of the balance, I would add a third point:
- (3) use a type that kind of reflects how the data is organised. E.g. when you can assume that the data does have a sequence, give
Seq. If you can assume that no two equal objects can occur, give aSet. Etc.
Here are my rules of thumb:
- try to use only a small set of collections:
Set,Map,Seq,IndexedSeq - I often violate this previous rule, though, using
Listin favour ofSeq. It allows the caller to do pattern matching with the cons extractors - use immutable types only (e.g.
collection.immutable.Set,collection.immutable.IndexedSeq) - do not use concrete implementations (
Vector), but the general type (IndexedSeq) which gives the same API - if you are encapsulating a mutable structure, only return
Iteratorinstances, the caller can then easily generate a strict structure, e.g. by callingtoListon it - if your API is small and clearly tuned towards “big data throughput”, use
IndexedSeq
Of course, this is my personal choice, but I hope it sounds sane.