Skip to content

Commit

Permalink
Migrating to viktorklang.com
Browse files Browse the repository at this point in the history
  • Loading branch information
viktorklang committed Apr 5, 2017
1 parent 0be7f05 commit 3d95425
Show file tree
Hide file tree
Showing 10 changed files with 10 additions and 640 deletions.
50 changes: 1 addition & 49 deletions Futures-in-Scala-2.12-part-1.md
Original file line number Diff line number Diff line change
@@ -1,49 +1 @@
# Futures in Scala 2.12 (part 1)

This is the first of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.

## Missing canonical combinators: flatten

Are you one of us Future-users who have grown tired of the old `flatMap(identity)` boilerplate for un-nesting `Future`s as in:

~~~scala
val future: Future[Future[X]] = ???
val flattenedFuture /*: Future[X] */ = future.flatMap(identity)
~~~

Then I have some great news for you!
Starting with Scala 2.12 `scala.concurrent.Future` will have a `flatten`-method with the following signature:

~~~scala
def flatten[S](implicit ev: T <:< Future[S]): Future[S]
~~~

Allowing you to write:

~~~scala
val future: Future[Future[X]] = ???
val flattenedFuture /*: Future[X] */ = future.flatten
~~~

### Benefits:

1. Less to type
2. Less to read
3. Does not require any `ExecutionContext`

**Bonus**: Doesn't allocate a function instance as `flatMap(identity)` does:

~~~scala
scala> def sameInstance[T](first: T => T, second: T => T) = first eq second
sameInstance: [T](first: T => T, second: T => T)Boolean

scala> sameInstance[Int](identity, identity)
res0: Boolean = false
~~~

[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-2.md) for the next part in this blog series.

Cheers,
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-1)
58 changes: 1 addition & 57 deletions Futures-in-Scala-2.12-part-2.md
Original file line number Diff line number Diff line change
@@ -1,57 +1 @@
# Futures in Scala 2.12 (part 2)

This is the second of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.
For the previous post, [click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-1.md).

## Missing canonical combinators: zipWith

Being able to *join* two `Future`s together to produce a new `Future`
which contains a `Tuple` of the results of both has been available for a while with the `zip` operation, and this looks something like this:

~~~scala
val future1: Future[String] =
val future2: Future[Int] =
val zippedFuture: Future[(String, Int)] = future1 zip future2
~~~

But what if we don't want a `Tuple`? What if we want to *combine* the results
of the two `Future`s to create something else?

This typically means having to combine `zip` and `map`:

~~~scala
/* The reason why we use a «PartialFunction literal» (yes, I made that up)
* here is because otherwise the code has to use the arguably uglier _._1 and
* _._2 syntax for `Tuple` value extraction.
*/
val combinedFuture: Future[String] =
future1 zip future2 map { case (string, int) => s"$string & $int" }
~~~

Now, if you're like me and you dislike allocations, tuples and lack of genericity, you'll see that `zip` is a specialization of `x.zipWith(y)(Tuple2.apply)`! Well, perhaps it helps if we share the signature of said `zipWith`:

~~~scala
def zipWith[U, R](that: Future[U])(f: (T, U) => R)(implicit executor: ExecutionContext): Future[R]
~~~

This allows us to express the example above as:

~~~scala
val combinedFuture: Future[String] =
future1.zipWith(future2)((string, int) => s"$string & $int")
~~~

### Benefits:

1. Less to type
2. Less to read
3. Fewer allocations
4. Fewer asynchronous steps
5. More general than `zip`

[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-3.md) for the next part in this blog series.

Cheers,
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-2)
62 changes: 1 addition & 61 deletions Futures-in-Scala-2.12-part-3.md
Original file line number Diff line number Diff line change
@@ -1,61 +1 @@
# Futures in Scala 2.12 (part 3)

This is the third of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.
For the previous post, [click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-2.md).

## Missing canonical combinators: transform

Now, if you're thinking "Hey Viktor, there's already a `transform`-method on `Future`!" then you're most definitely right. And I'll explain myself.

When the old `transform`<sup>[1](#transformNote)</sup> was added, many moons ago, it was a means of mapping over successes and failures. However, the astute reader might notice that it is asymmetric: an exception thrown when mapping over the successful case will result in a failed `Future`, but there is no way to turn a failed case into a successful one.

One way of looking at a `scala.concurrent.Future` is that it's an "`Eventually[Try[_]]`", in other words, a container which will eventually contain a `scala.util.Try` parameterized by some type.

What if we had a way to *transform* `Future` more generically, and symmetrically?

Perhaps its signature ought to look something like this:

~~~scala
def transform[S](f: Try[T] => Try[S])(implicit executor: ExecutionContext): Future[S]
~~~

So for instance, that would mean that `Future.map` could be implemented as follows (and is!):

~~~scala
def map[S](f: T => S)(implicit executor: ExecutionContext): Future[S] = transform(_.map(f))
~~~

And `Future.recover` is possible to implement as this (and is!):

~~~scala
def recover[U >: T](pf: PartialFunction[Throwable, U])(implicit executor: ExecutionContext): Future[U] =
transform { _ recover pf }
~~~

It also makes it *dead simple* to *lift* a `Future[T]` to a `Future[Try[T]]`:

~~~scala
val someFuture: Future[String] =
val lifted/*: Future[Try[String]]*/ = someFuture.transform(Try(_))
~~~

Nice, right?


### Benefits:

1. Strictly more powerful / generic than the previous `transform`-method
2. Straightforward to consume/transform a `Future`s `Try[_]` without having to use `onComplete` or unboxing `Future.value`
3. For implementors of the `Future` trait, less methods to implement

[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-4.md) for the next part in this blog series.

Cheers,

<a name="transformNote">1</a>:
~~~scala
def transform[S](s: T => S, f: Throwable => Throwable)(implicit executor: ExecutionContext): Future[S]
~~~
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-3)
53 changes: 1 addition & 52 deletions Futures-in-Scala-2.12-part-4.md
Original file line number Diff line number Diff line change
@@ -1,52 +1 @@
# Futures in Scala 2.12 (part 4)

This is the fourth of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.
For the previous post, [click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-3.md).

## Missing canonical combinators: transformWith

As we saw in the previous post, `transform` provides a nice unification of both `map` and `recover` on `Future`, and I know what you're thinking now: "What about `flatMap` and `recoverWith`?"

Say no more! `transformWith` is the answer, and has the following lovely signature:

~~~scala
def transformWith[S](f: Try[T] => Future[S])(implicit executor: ExecutionContext): Future[S]
~~~

Remember to use the solution with the least power which will suffice for the task at hand, so prefer to use the `flatMap`s and the `recoverWith`s primarily, opting for the `transformWith` as required.

And, before you say anything, yes, `flatMap` and `recoverWith` are implemented in terms of `transformWith` in Scala 2.12!

EDIT:

Here's `flatMap`:

~~~scala
def flatMap[S](f: T => Future[S])(implicit executor: ExecutionContext): Future[S] = transformWith {
case Success(s) => f(s)
case Failure(_) => this.asInstanceOf[Future[S]] //Safe cast to reuse current, failed, Future
}
~~~

And here's `recoverWith`:

~~~scala
def recoverWith[U >: T](pf: PartialFunction[Throwable, Future[U]])(implicit executor: ExecutionContext): Future[U] =
transformWith {
case Failure(t) => pf.applyOrElse(t, (_: Throwable) => this) //Pass along current failure if no match
case Success(_) => this
}
~~~

### Benefits:

1. Ultimate power, for when you require it

[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

To comment on the blog post itself, [click here](https://github.com/viktorklang/blog/pull/4/files) or [here](https://github.com/viktorklang/blog/pull/6/files) and comment on the PR.

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-5.md) for the next part in this blog series.

Cheers,
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-4)
54 changes: 1 addition & 53 deletions Futures-in-Scala-2.12-part-5.md
Original file line number Diff line number Diff line change
@@ -1,53 +1 @@
# Futures in Scala 2.12 (part 5)

This is the fifth of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.
For the previous post, [click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-4.md).

## Deprecations: onSuccess and onFailure

Since its inception and subsequent inclusion in the Scala Standard Library, `Future` has had 3 distinctly identifiable callback methods. `onComplete`, `onSuccess`, and `onFailure`.

Now, you're perhaps asking yourself why it is that `onSuccess` and `onFailure` are special-cases of `onComplete`, operating on eiter side of success/failure? Well, at some point it was conceived as useful.

"But…", I hear you say, "isn't `foreach` *just* a total version of `onSuccess`?" Well, yes it is. So let's use that instead, or `onComplete`!


So, if you call `someFuture.onSuccess(somePartialFunction)` in Scala 2.12.x you'll get the following deprecation message:

~~~txt
use `foreach` or `onComplete` instead (keep in mind that they take total rather than partial functions)
~~~

And then I hear you thinking "But, if `onSuccess` is the partial version of `foreach`, doesn't that mean that `onFailure` is the partial version of `failed.foreach`?" YES—exactly that!

This is why `someFuture.onFailure(somePartialFunction)´ in Scala 2.12.x yields this deprecation message:

~~~txt
use `onComplete` or `failed.foreach` instead (keep in mind that they take total rather than partial functions)
~~~

Worth keeping in mind, as with all the callbacks & `foreach`—there is no guaranteed order of execution of callbacks attached to the same `Future`.
To illustrate:

~~~scala
val someFuture: Future[Missile] =
someFuture.foreach(_.neutralize(PERMANENTLY))
someFuture.foreach(_.launch(target))
//Could be executed in any order and not unlikely in parallel
~~~

### Benefits:

1. Promotion of for-comprehension compatible API instead of callbacks
2. In the end there'll be fewer methods on Future, being less confusing as to what to use and when
3. `onComplete` then remains as a performance-optimization of [`transform`](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-3.md), not having to create `Future`s to return.


[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

To comment on the blog post itself, [click here](https://github.com/viktorklang/blog/pull/7/files) and comment on the PR.

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-6.md) for the next part in this blog series.

Cheers,
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-5)
88 changes: 1 addition & 87 deletions Futures-in-Scala-2.12-part-6.md
Original file line number Diff line number Diff line change
@@ -1,87 +1 @@
# Futures in Scala 2.12 (part 6)

This is the sixth of several posts describing the evolution of `scala.concurrent.Future` in Scala `2.12.x`.
For the previous post, [click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-5.md).

## Missing utilities: unit & never

Something I've always felt was missing is having a «zero» for `Future`—or more frequently called a «default instance» of a `Future`.

What's *nice* about having this is that, technically, `Future.apply[T](logic: => T)(implicit ec: ExecutionContext)` could be viewed as, and implemented like:

~~~scala
def apply[T](logic: => T)(implicit ec: ExecutionContext): Future[T] =
unit.map(_ => logic)
~~~

Q: Where is it useful?
A: Anywhere you have `Future.successful(())`

Example:

~~~scala
//Imagine we don't want to try to store nulls or empty strings
//Returns a Future[Unit] which will be completed once the operation has completed
def storeInDB(s: String): Future[Unit] = s match {
case null | "" => Future.unit
case other => db.store(s)
}

val f: Future[String] =
val f2 = f flatMap storeInDB
~~~

Another important scenario, which wasn't really readily solvable unless you were comfortable with implementing it yourself was a `Future` which would never complete.

Now, the naïve implemention of said `Future` would look something like:

~~~scala
val neverCompletingFuture: Future[Nothing] = Promise[Nothing].future
~~~

Take a few seconds to think about the following question: In what ways would that solution be undesirable?





Hint: What happens with logic which gets added to `neverCompletingFuture`?
Example:

~~~scala
val fooFuture = neverCompletingFuture.map(_ => "foo")

//or

neverCompletingFuture.onComplete(println)
~~~

Well, what happens is that the logic is *packaged* and added to the `neverCompletingFuture` instance in order to be executed when `neverCompletingFuture` completes (which is never), and now we have a hard to spot invisible memory leak!

So, in order to support the case when you want to be able to represent a `Future` which never completes, but also doesn't leak memory when used as a plain `Future`, use `Future.never`.

An example use-case might be when you need to pass in a Future which should not affect the outcome, as in:

~~~scala
val someImportantFuture: Future[String] =
val someLessImportantFuture: Future[String] = if (someCondition) Future.never else Future.successful("pigdog")
val first = Future.firstCompletedOf(someImportantFuture, someLessImportantFuture) // Will always pick someImportantFuture if someCondition is true
~~~

### Benefits:

1. Future.unit is a «zero» instance which is cached
2. Future.never removes the risk of memory leaks when used as a `Future` instance which never completes

[Here's the RSS feed of this blog](https://github.com/viktorklang/blog/commits/master.atom) and—as I love feedback—please [share your thoughts](https://github.com/viktorklang/blog/issues/3).

To comment on the blog post itself, [click here](https://github.com/viktorklang/blog/pull/8/files).

[Click here](https://github.com/viktorklang/blog/blob/master/Futures-in-Scala-2.12-part-7.md) for the next part in this blog series.

Cheers,
This post has moved to [here](http://viktorklang.com/blog/Futures-in-Scala-2.12-part-6)
Loading

0 comments on commit 3d95425

Please sign in to comment.