Filter on future doesn't make sense

1,412 views
Skip to first unread message

Avi Levi

unread,
Jul 1, 2016, 2:53:55 AM7/1/16
to scala-language
I was trying to figure out what should I accept when filtering over a future .
the current implementation yields either a T or an exception which kind of breaks referential transparency (doesn't it ?) .
on the other hand what can I expect given this expression 

def foo(i:Int):Future[Int]

the type result of 

foo(1).filter(_ % 2 == 0)


I.M.H.O I would expect it to yield Option[T]  which makes more sense to express that we might get a value that pass the filter or not . is that make sense ?

Cheers
Avi 

Viktor Klang

unread,
Jul 1, 2016, 3:06:45 AM7/1/16
to scala-l...@googlegroups.com

Hi Avi,

Use Fututre[Option[Int]] if you want to deal with Some/None as a result of filter ( f.map(_.filter(p) ) (alt. see monad transformers)

--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-language" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-languag...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.

Avi Levi

unread,
Jul 1, 2016, 3:20:43 AM7/1/16
to scala-l...@googlegroups.com

Thanks Victor,
Of course it can be implemented as you suggested. But still I can argue that the current implementation is not "really filtering" the results as one might expect and less expressive if it might or not return the value than Option is more expressive, don't you agree?

You received this message because you are subscribed to a topic in the Google Groups "scala-language" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-language/wpGOB8f7qmY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-languag...@googlegroups.com.

Viktor Klang

unread,
Jul 1, 2016, 3:50:19 AM7/1/16
to scala-l...@googlegroups.com

Hi Avi,

I see what you mean.

I'd want to avoid discussing expectation since it is subjective. I will however note that the actualnsemantics of the filter method on Future needs improvement: http://www.scala-lang.org/api/2.11.8/index.html#scala.concurrent.Future@filter(p:T=>Boolean)(implicitexecutor:scala.concurrent.ExecutionContext):scala.concurrent.Future[T]

As for might not return the value, the same goes for all filter-methods:

List returns List, but it might not have any elements at all. Option returns Option but can be Some or None, Future is either Success or Failure.

If success has an optionality aspect in your usage, use Future of Option to express that, that would be my recommendation.

--
Cheers,

Avi Levi

unread,
Jul 1, 2016, 4:35:46 AM7/1/16
to scala-l...@googlegroups.com
Hi Victor ,
I totally agree that expectations are subjective .
But like you said a filter on List will return a List if no element comply than we will get Nil which represents an empty container (empty list)
a filter on option will return a option if the element doesn't comply than we will get None which represents an empty container 
following the same logic a filter on future should return something that express empty container , defiantly not an exception, because it is not an exception we do intend to filter those elements.

 

Viktor Klang

unread,
Jul 1, 2016, 5:30:55 AM7/1/16
to scala-l...@googlegroups.com

But you don't get an exception on the success path. All operations on the success path will be skipped, just as for Option.

--
Cheers,

Avi Levi

unread,
Jul 1, 2016, 5:36:37 AM7/1/16
to scala-l...@googlegroups.com

Correct, just on future you get an exception if element does not pass the filter. Wouldn't it be better if we can get something that express an empty future?

Viktor Klang

unread,
Jul 1, 2016, 5:44:47 AM7/1/16
to scala-l...@googlegroups.com

I think you are conflating the notion of optionality here.

option.filter(p).map(f).foreach(println)

behaves exactly like

future.filter(p).map(f).foreach(println)

--
Cheers,

Oliver Ruebenacker

unread,
Jul 1, 2016, 8:54:48 AM7/1/16
to scala-l...@googlegroups.com

     Hello,

  Looks like sometimes you do get an exception:

Welcome to Scala 2.11.8 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_45).
Type in expressions for evaluation. Or try :help.

scala> import scala.concurrent.Future
import scala.concurrent.Future

scala> import scala.concurrent.ExecutionContext.Implicits.global
import scala.concurrent.ExecutionContext.Implicits.global

scala> Future{1}.onComplete { case _ => println("Complete!") }

scala> Complete!


scala> Future{1}.filter(_ == 0).onComplete { case _ => println("Complete!") }
Complete!

scala> import scala.util.{Success, Failure }
import scala.util.{Success, Failure}

scala> Future{1}.filter(_ == 0).onComplete {
     | case Success(value) => println(value)
     | case Failure(ex) => println(ex)
     | }

java.util.NoSuchElementException: Future.filter predicate is not satisfied
scala>


     Best, Oliver

Oliver Ruebenacker
Senior Software Engineer, Diabetes Portal, Broad Institute

Viktor Klang

unread,
Jul 1, 2016, 9:02:18 AM7/1/16
to scala-l...@googlegroups.com

Hi Oliver,

Which is why I explicitly talked about the success path.
As you saw, onComplete takes both path, much similar to something like toString.

See my previous example for details.

--
Cheers,

Roland Kuhn

unread,
Jul 1, 2016, 9:06:42 AM7/1/16
to scala-l...@googlegroups.com
The difference is that Option does not have onComplete: if you restrict yourself to the Option API then Future behaves observably in the same way. If you want to have something like onComplete you should look at Either[NoSuchElementException, T]#fold.

In general there is no .filter on monads because that would require the explicit ability to represent emptiness (which is not part of the contract); the success path for the combinators could be seen as such a representation and it is indeed often used as such, so Future is quite well-behaved in this regard. Another comment I’d like to make on the discussed change is that it is not reasonable to expect that the result of filtering returns a different type than the original one—no other container has this behavior.

Regards,

Roland

Oliver Ruebenacker

unread,
Jul 1, 2016, 9:16:06 AM7/1/16
to scala-l...@googlegroups.com

     Hello Viktor,

  I see. I thought you meant with "success path" that the original Future succeeds, but apparently you mean that also all filters are satisfied.

     Best, Oliver

Oliver Ruebenacker

unread,
Jul 1, 2016, 9:18:19 AM7/1/16
to scala-l...@googlegroups.com

     Hello Roland,

  Option has get, getOrElse and the possibility to match against Some(value), but Future does not have these.

     Best, Oliver

Roland Kuhn

unread,
Jul 1, 2016, 10:02:14 AM7/1/16
to scala-l...@googlegroups.com
Well … technically (and no, this is NOT a good idea, and hence it looks a little odd):

scala> import concurrent._
import concurrent._

scala> import ExecutionContext.Implicits._
import ExecutionContext.Implicits._

scala> import duration._
import duration._

scala> Future(42)
res0: scala.concurrent.Future[Int] = scala.concurrent.impl.Promise$DefaultPromise@25bbf683

scala> Await.ready(res0, 1.second).value.get.toOption
res1: Option[Int] = Some(42)

scala> Await.ready(res0.filter(_ == 1), 1.second).value.get.toOption
res2: Option[Int] = None

Regards,

Roland

Avi Levi

unread,
Jul 1, 2016, 10:17:02 AM7/1/16
to scala-l...@googlegroups.com
Hi Ronald ,
taking the example above 
scala>val x = Future{1}.filter(_ == 0)
scala>x.value
res2: Option[scala.util.Try[Int]] = Some(Failure(java.util.NoSuchElementException: Future.filter predicate is not satisfied))

It seems odd that a legit action such as filter yields a failure with an exception . 

Cheers 
Avi

Oliver Ruebenacker

unread,
Jul 1, 2016, 1:51:00 PM7/1/16
to scala-l...@googlegroups.com

     Hello,

  But that's consistent with options and collections:

scala> Some(1).filter(_ == 0).get
java.util.NoSuchElementException: None.get

scala> Set(1, 2, 3).filter(_ == 0).head
java.util.NoSuchElementException: next on empty iterator

     Best, Oliver

Viktor Klang

unread,
Jul 1, 2016, 1:52:33 PM7/1/16
to scala-l...@googlegroups.com

Hi Avi,

I'm unsure "seems odd" can be discussed successfully, I'm afraid.

As have been demonstrated, filter on Future behaves semantically equivalent to the methods used by for-comprehensions (map, flatMap, filter/withFilter and foreach)

--
Cheers,

Avi Levi

unread,
Jul 1, 2016, 2:12:44 PM7/1/16
to scala-l...@googlegroups.com
Viktor, Oliver 
I guess you are correct .
But 
scala> Some(1).filter(_ == 0)
res0: Option[Int] = None
scala> Set(1, 2, 3).filter(_ == 0)
res1: scala.collection.immutable.Set[Int] = Set()
BUT
val x = Future{1}.filter(_ == 0)
Failure(java.util.NoSuchElementException: Future.filter predicate is not satisfied))


Roland Kuhn

unread,
Jul 1, 2016, 2:29:02 PM7/1/16
to scala-l...@googlegroups.com
To my mind the moral to be learnt from this example is that

  • pattern matching on internal structure of the container is potentially inconsistent
  • monadic combinators (and similar extensions) are more careful in avoiding the exposure of internal details

Whether or not this seems odd lies in the eye of the beholder, but from a theoretical perspective that’s just how it is.

Regards,

Roland

Viktor Klang

unread,
Jul 1, 2016, 2:48:51 PM7/1/16
to scala-l...@googlegroups.com
On Fri, Jul 1, 2016 at 8:12 PM, Avi Levi <123...@gmail.com> wrote:
Viktor, Oliver 
I guess you are correct .
But 
scala> Some(1).filter(_ == 0)
res0: Option[Int] = None
scala> Set(1, 2, 3).filter(_ == 0)
res1: scala.collection.immutable.Set[Int] = Set()
BUT
val x = Future{1}.filter(_ == 0)
Failure(java.util.NoSuchElementException: Future.filter predicate is not satisfied))

So you'd be happy(?) if the toString on a failed future said "Future()"?

(Keep in mind the comment I had about toString earlier in the thread :))



--
Cheers,

Naftoli Gugenheim

unread,
Jul 10, 2016, 1:19:22 AM7/10/16
to scala-language


On Fri, Jul 1, 2016, 2:53 AM Avi Levi <123...@gmail.com> wrote:
I was trying to figure out what should I accept when filtering over a future .
the current implementation yields either a T or an exception which kind of breaks referential transparency (doesn't it ?) .

How would it break referential transparency? It's just a value that happens to extend Throwable. (Actually throwing an exception might break RT, but that's not happening.)

Isn't there the same question about Try#filter?



on the other hand what can I expect given this expression 

def foo(i:Int):Future[Int]

the type result of 

foo(1).filter(_ % 2 == 0)


I.M.H.O I would expect it to yield Option[T]  which makes more sense to express that we might get a value that pass the filter or not . is that make sense ?

Cheers
Avi 

--

Avi Levi

unread,
Jul 10, 2016, 3:19:49 AM7/10/16
to scala-l...@googlegroups.com

Yeah, you are right . I take that back

You received this message because you are subscribed to a topic in the Google Groups "scala-language" group.
To unsubscribe from this topic, visit https://groups.google.com/d/topic/scala-language/wpGOB8f7qmY/unsubscribe.
To unsubscribe from this group and all its topics, send an email to scala-languag...@googlegroups.com.
Reply all
Reply to author
Forward
0 new messages