Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How do I deal with Scala collections generically?

I have realized that my typical way of passing Scala collections around could use some improvement.

def doSomethingCool(theFoos: List[Foo]) = { /* insert cool stuff here */ }

// if I happen to have a List
doSomethingCool(theFoos)

// but elsewhere I may have a Vector, Set, Option, ...
doSomethingCool(theFoos.toList)

I tend to write my library functions to take a List as the parameter type, but I'm certain that there's something more general I can put there to avoid all the occasional .toList calls I have in the application code. This is especially annoying since my doSomethingCool function typically only needs to call map, flatMap and filter, which are defined on all the collection types.

What are my options for that 'something more general'?

like image 972
leedm777 Avatar asked Dec 27 '22 08:12

leedm777


1 Answers

Here are more general traits, each of which extends the previous one:

  • GenTraversableOnce
  • GenTraversable
  • GenIterable
  • GenSeq

The traits above do not specify whether the collection is sequential or parallel. If your code requires that things be executed sequentially (typically, if your code has side effects of any kind), they are too general for it.

The following traits mandate sequential execution:

  • TraversableOnce
  • Traversable
  • Iterable
  • Seq
  • LinearSeq

The first one, TraversableOnce only allows you to call one method on the collection. After that, the collection has been "used". In exchange, it is general enough to accept iterators as well as collections.

Traversable is a pretty general collection that has most methods. There are some things it cannot do, however, in which case you need to go to Iterable.

All Iterable implement the iterator method, which allows you to get an Iterator for that collection. This gives it the capability for a few methods not present in Traversable.

A Seq[A] implements the function Int => A, which means you can access any element by its index. This is not guaranteed to be efficient, but it is a guarantee that each element has an index, and that you can make assertions about what that index is going to be. Contrast this with Map and Set, where you cannot tell what the index of an element is.

A LinearSeq is a Seq that provides fast head, tail, isEmpty and prepend. This is as close as you can get to a List without actually using a List explicitly.

Alternatively, you could have an IndexedSeq, which has fast indexed access (something List does not provide).

See also this question and this FAQ based on it.

like image 165
Daniel C. Sobral Avatar answered Jan 11 '23 23:01

Daniel C. Sobral