Some questions regarding Futures (SIP 14)

100 views
Skip to first unread message

Heiko Seeberger

unread,
May 14, 2012, 11:06:46 AM5/14/12
to scala...@googlegroups.com
Hi,

Some questions:

(I)
Why do Future.onSuccess and Future.onFailure take a PartialFunction instead of a function? If it were a function the code could be more concise.

val f: Future[List[String]] = ...
f onSuccess {
  case posts => posts foreach println
}

could be rewritten:

val f: Future[List[String]] = ...
f onSuccess (_  foreach println)

(II)
Why does Future.foreach have a type parameter? Wouldn't Future.foreach(f: T => Any): Unit be simpler and equally good?

(III)
Why do Future.onSuccess/onFailure no longer return Future.this.type?

Thanks
Heiko

--

Heiko Seeberger
Twitter: hseeberger
Blog: heikoseeberger.name
Company: Typesafe - The software stack for applications that scale
Author of Durchstarten mit Scala, a German tutorial-style Scala book


√iktor Ҡlang

unread,
May 14, 2012, 11:17:04 AM5/14/12
to scala...@googlegroups.com
Hi,

On Mon, May 14, 2012 at 5:06 PM, Heiko Seeberger <heiko.s...@googlemail.com> wrote:
Hi,

Some questions:

(I)
Why do Future.onSuccess and Future.onFailure take a PartialFunction instead of a function? If it were a function the code could be more concise.

val f: Future[List[String]] = ...
f onSuccess {
  case posts => posts foreach println
}

That was a trade-off between submitting tasks that weren't going to execute anyway.
 

could be rewritten:

val f: Future[List[String]] = ...
f onSuccess (_  foreach println)

It's a fair point that might be possible to revisit since partial functions extend function.
 

(II)
Why does Future.foreach have a type parameter? Wouldn't Future.foreach(f: T => Any): Unit be simpler and equally good?

Because of type inference issues.
 

(III)
Why do Future.onSuccess/onFailure no longer return Future.this.type?

Because one could be lured into believing that there was an ordering between callbacks.

future onSuccess {
  case "badass" => doSomething
} map { _.toUpperCase } //There's a subtle implication that toUpperCase will be performed AFTER doSomething, which is not true.
 

Also, please note that programming with onX is not good practice and should be used when extending futures. Prefer the transformations like map/filter/flatMap/transform etc

Cheers,


Thanks
Heiko

--

Heiko Seeberger
Twitter: hseeberger
Blog: heikoseeberger.name
Company: Typesafe - The software stack for applications that scale
Author of Durchstarten mit Scala, a German tutorial-style Scala book





--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

Stefan Zeiger

unread,
May 14, 2012, 11:31:04 AM5/14/12
to scala...@googlegroups.com
On 2012-05-14 17:17, √iktor Ҡlang wrote:

(II)
Why does Future.foreach have a type parameter? Wouldn't Future.foreach(f: T => Any): Unit be simpler and equally good?

Because of type inference issues.

Could you explain what issues you encountered that did not show up here? https://groups.google.com/forum/#!msg/scala-internals/WcjhL2CVG38/rLYhE7TpxtsJ

Cheers,
Stefan

Derek Williams

unread,
May 14, 2012, 11:34:47 AM5/14/12
to scala...@googlegroups.com
On Mon, May 14, 2012 at 9:06 AM, Heiko Seeberger <heiko.s...@googlemail.com> wrote:
(I)
Why do Future.onSuccess and Future.onFailure take a PartialFunction instead of a function? If it were a function the code could be more concise.

I've previously tried changing onSuccess/onFailure to take a function, and then check if the function is a PartialFunction to keep the same behaviour that it has now. I believe it worked if I passed it an actual instance of a PartialFunction, but if I did something like this:

f onSuccess {
  case posts if posts.nonEmpty => println(posts.mkString)
}

it seems like that gets transformed into:

f onSucces { _ match {
  case posts if posts.nonEmpty => println(posts.mkString)
}}

which is not a PartialFunction, so a MatchError would be thrown if there was no match. I haven't checked how exceptions are displayed in SIP 14, but in Akka that used to cause unwanted exceptions being logged.

--
Derek Williams

Aleksandar Prokopec

unread,
May 14, 2012, 11:42:26 AM5/14/12
to scala...@googlegroups.com, Heiko Seeberger
On 5/14/12 5:06 PM, Heiko Seeberger wrote:
> Hi,
>
> Some questions:
>
> (I)
> Why do Future.onSuccess and Future.onFailure take a PartialFunction
> instead of a function? If it were a function the code could be more
> concise.
>
> val f: Future[List[String]] = ...
> f onSuccess {
> case posts => posts foreach println
> }
>
> could be rewritten:
>
> val f: Future[List[String]] = ...
> f onSuccess (_ foreach println)
>
> (II)
> Why does Future.foreach have a type parameter? Wouldn't
> Future.foreach(f: T => Any): Unit be simpler and equally good?
>

We could have alternatively have:

def foreach(f: T => Unit)

but then calling:

val func = (x: Int) => {println(); x * 2}
val f = future { 1 }
f.foreach(func)

wouldn't work.

I guess def foreach(f: T => Any) is an ok alternative, but with the:

def foreach[U](f: T => U): Unit

we're more in sync with the collections which have this signature.

So, what are the type inference issues with foreach(f: T => Any)? I must
have missed something.

Thanks,
Alex



--
Aleksandar Prokopec,
Doctoral Assistant
LAMP, IC, EPFL
http://people.epfl.ch/aleksandar.prokopec

√iktor Ҡlang

unread,
May 14, 2012, 12:05:41 PM5/14/12
to scala...@googlegroups.com, Heiko Seeberger
Don't remember, could have been type inference with Nothing?

Cheers,
 

Thanks,
Alex



--
Aleksandar Prokopec,
Doctoral Assistant
LAMP, IC, EPFL
http://people.epfl.ch/aleksandar.prokopec




--
Viktor Klang

Akka Tech Lead
Typesafe - The software stack for applications that scale

Twitter: @viktorklang

√iktor Ҡlang

unread,
May 14, 2012, 12:31:24 PM5/14/12
to scala...@googlegroups.com
Sorry, I didnt do a whitepaper on it.
Might've been back in 2.7 or 2.8 for all I remember.
 


Cheers,
Stefan

Heiko Seeberger

unread,
May 14, 2012, 4:08:07 PM5/14/12
to scala...@googlegroups.com
On May 14, 2012, at 5:17 PM, √iktor Ҡlang wrote:

> It's a fair point that might be possible to revisit since partial functions extend function.

Having 1/3 of my points considered potentially revisitable is awesome ;-)

Heiko

√iktor Ҡlang

unread,
May 14, 2012, 4:48:23 PM5/14/12
to scala...@googlegroups.com
I hope you wouldn't want to change onX back to returning this.type and the foreach-thingy is how it's rolled in the std lib already, right? :-)
 

Heiko

Heiko Seeberger

unread,
May 14, 2012, 4:58:28 PM5/14/12
to scala...@googlegroups.com
On May 14, 2012, at 10:48 PM, √iktor Ҡlang wrote:

> I hope you wouldn't want to change onX back to returning this.type

Pawn sacrifice ;-)

> and the foreach-thingy is how it's rolled in the std lib already, right? :-)

Well, at least I would like to understand. The std lib is not necessarily always right. And if there is a chance to make it simpler without any sacrifice, why not?

Heiko

√iktor Ҡlang

unread,
May 14, 2012, 5:30:33 PM5/14/12
to scala...@googlegroups.com
On Mon, May 14, 2012 at 10:58 PM, Heiko Seeberger <heiko.s...@googlemail.com> wrote:
On May 14, 2012, at 10:48 PM, √iktor Ҡlang wrote:

> I hope you wouldn't want to change onX back to returning this.type

Pawn sacrifice ;-)


Lol
 
> and the foreach-thingy is how it's rolled in the std lib already, right? :-)

Well, at least I would like to understand. The std lib is not necessarily always right. And if there is a chance to make it simpler without any sacrifice, why not?

Sure, but it needs to be proven that it works for all cases.

Cheers,
 

Heiko
 

Aleksandar Prokopec

unread,
May 14, 2012, 5:30:51 PM5/14/12
to scala...@googlegroups.com
I usually take a bit of a superstitious stand on advocating foreach[U](f: T => U): Unit, since that approach is taken in the collections library.
So, I must admit I'm not sure myself what are the downsides of foreach(f: T => Any).
Reply all
Reply to author
Forward
0 new messages