Hi,
so, to the point, I had the following trait (as an interface for abstracting many possible implementations of a repository):
trait FooRepository {
...
def exists(fooId: Id): Future[Boolean]
def asFilterFor(ids: Seq[Id]): Future[Seq[Id]] // Filter a sequence of ids against the existing ids
...
}
As you can see all the operations return eventual results, for this would be connected against some remote data store. In particular, asFilterFor implementation looked like this:
def asFilterFor(ids: Seq[Id]): Future[Seq[Id]] = Future.sequence(ids.map(someIfExists)).map(_.flatten)
// .option is Scalaz boolean-to-option utility: this is, Some(id) if true, None otherwise
private def someIfExists(id: Id) = exists(id).map(_.option(id))
Then I realized that asFilterFor would be used against more types of collections, so it seemed natural to implement it for any traversable. I thought it was going to be easy but ended up struggling a lot with the language, till I got something that worked:
def asFilterFor[C[Id] <: Traversable[Id]]
(ids: Seq[Id])(implicit
bf1: CanBuildFrom[C[Id], Future[Option[Id]], C[Future[Option[Id]]]],
bf2: CanBuildFrom[C[Future[Option[Id]]], Option[Id], C[Option[Id]]]
): Future[C[Id]] =
Future.sequence(ids.map(someIfExists)).map(_.flatten).asInstanceOf[Future[C[Id]]]
Woooow, needless is to say that this is very neat implementation of an outrageously frightful method signature. So my questions would be:
1) doesn't this signature expose implementation details by means of the implicit parameters (the two CanBuildFrom)?
2) is there anything I can do about it or any cleaner alternative for generalizing such a method?
Thanks in advance,
Tom;
PD: Names of methods aren't the real ones, of course.