Future.andThen should be deprecated

Previous Topic Next Topic
 
classic Classic list List threaded Threaded
16 messages Options
Reply | Threaded
Open this post in threaded view
|

Future.andThen should be deprecated

Tim Harper
I think the behavior is tremendously surprising. That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

I think `Future.onComplete` is wholly sufficient to modify side effecting code. Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.

I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

Tim

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang


On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?
 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Tim Harper

On Feb 4, 2016, at 14:58, Viktor Klang <[hidden email]> wrote:



On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?
 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

Okay, the lack of exception affecting it led me to believe otherwise.

This method allows one to enforce that the callbacks are executed in a specified order.
Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.
The following example prints out 5:
val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

Why are people writing code like this? IMO that's a horrible way to write imperative programs. It's clearer (and better) to just write it like this:

future.onComplete {
  case _ =>
    scheduleLaunchOfMissiles()
    cancelScheduledLaunchOfMissiles()
}

If you don't want exceptions to interfere with the execution, then surround with Try and ignore the result.

If you really must inject a function that only affects a Future by adding a delay, and you don't want exceptions to propagate (and maybe my problem is I'm having a hard time imagining a scenario in which I'd want that), then it's already achieveable by using map:

future.map { r =>
  try {
    someStatefulThing()
  } catch {
    case e: Throwable =>
      # completely ignore LOL
  }
  r
}

It's more verbose but I find it difficult to convince myself that what seems to be a special case such as this needs to be verbose.


In which order will the above be executed?
 

Tim


--
Cheers,

Cheers :)

Tim

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Tim Harper
Sorry, this sentence was horrible:

It's more verbose but I find it difficult to convince myself that what seems to be a special case such as this needs to be verbose.

It's more verbose, but I find this to be a special case, and I strongly believe that here, the verbosity is warranted.

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Naftoli Gugenheim
In reply to this post by Viktor Klang


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Why have a method "only for side effecting"?

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

If it's for side-effecting then why is it chainable?

If the results are run in sequence then why isn't the last value available? In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
  • Something like map except Try[T] => Try[U]
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Kevin Wright-3

  • Something like flatMap that whose function takes a Try[T] instead of a T
  • Something like map except Try[T] => Try[U]
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]
Lots of +1s here… I’ve had to implement every single one of these for myself at one time or another.  Conceptually, this is much the same thing as the materialise/dematerialise operations in Rx.


On 4 February 2016 at 23:05, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Why have a method "only for side effecting"?

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

If it's for side-effecting then why is it chainable?

If the results are run in sequence then why isn't the last value available? In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
  • Something like map except Try[T] => Try[U]
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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

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



--
Kevin Wright
mail: [hidden email]
gtalk / msn : [hidden email]
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang
In reply to this post by Tim Harper


On Thu, Feb 4, 2016 at 11:09 PM, Tim Harper <[hidden email]> wrote:

On Feb 4, 2016, at 14:58, Viktor Klang <[hidden email]> wrote:



On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?
 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

Okay, the lack of exception affecting it led me to believe otherwise.

Yes, I think that the documentation is poorly worded there, it should refer to "value" and not "result" IMO, as result easily gets biased to "successful result".
 

This method allows one to enforce that the callbacks are executed in a specified order.
Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.
The following example prints out 5:
val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

Why are people writing code like this?

someLibrary.someMethod(future)
someOtherLibrary.someOtherMethod(future)

 
IMO that's a horrible way to write imperative programs. It's clearer (and better) to just write it like this:

future.onComplete {
  case _ =>
    scheduleLaunchOfMissiles()
    cancelScheduledLaunchOfMissiles()
}

Yes, of course, if you happen to have this logic in the same place.
 

If you don't want exceptions to interfere with the execution, then surround with Try and ignore the result.

Sure, but that is *technically* not what happens, as any exception thrown by the side-effect is reported to the ExecutionContext.
 

If you really must inject a function that only affects a Future by adding a delay, and you don't want exceptions to propagate (and maybe my problem is I'm having a hard time imagining a scenario in which I'd want that), then it's already achieveable by using map:

future.map { r =>
  try {
    someStatefulThing()
  } catch {
    case e: Throwable =>
      # completely ignore LOL
  }
  r
}

That will not execute the side effect if the Future failed.
 

It's more verbose but I find it difficult to convince myself that what seems to be a special case such as this needs to be verbose.

This will get better in 2.12 (see the replies to the thread I have yet to write, after this reply)
 


In which order will the above be executed?

You didn't answer my question, Tim. :)

 
 

Tim


--
Cheers,

Cheers :)

Tim




--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang
In reply to this post by Naftoli Gugenheim
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).
 

Why have a method "only for side effecting"?

You mean like `foreach`?
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?
 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang
In reply to this post by Kevin Wright-3
Kevin, see my reply to Naftoli.

On Fri, Feb 5, 2016 at 10:23 AM, Kevin Wright <[hidden email]> wrote:

  • Something like flatMap that whose function takes a Try[T] instead of a T
  • Something like map except Try[T] => Try[U]
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]
Lots of +1s here… I’ve had to implement every single one of these for myself at one time or another.  Conceptually, this is much the same thing as the materialise/dematerialise operations in Rx.


On 4 February 2016 at 23:05, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Why have a method "only for side effecting"?

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

If it's for side-effecting then why is it chainable?

If the results are run in sequence then why isn't the last value available? In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
  • Something like map except Try[T] => Try[U]
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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

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



--
Kevin Wright
mail: [hidden email]
gtalk / msn : [hidden email]
vibe / skype: kev.lee.wright
steam: kev_lee_wright

"My point today is that, if we wish to count lines of code, we should not regard them as "lines produced" but as "lines spent": the current conventional wisdom is so foolish as to book that count on the wrong side of the ledger" ~ Dijkstra



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Tim Harper
In reply to this post by Viktor Klang


On Friday, February 5, 2016 at 6:08:37 AM UTC-7, √iktor Klang wrote:

In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

If the value is not used then the PartialFunction should be expected to return Unit. That way the compiler can at least say "hey pure expression here does nothing LOL are you sure?"



In which order will the above be executed?
You didn't answer my question, Tim. :)

It's indeterministic :)

future.map { r =>
  try {
    someStatefulThing()
  } catch {
    case e: Throwable =>
      # completely ignore LOL
  }
  r
}
That will not execute the side effect if the Future failed.

Fair point.

So, there's inertia that there's use to the function (and while I can agree, I still believe the style of programming it encourages should be avoided at almost all costs), I think I could be satisfied with the following:
  • The function is renamed to something else, since andThen is used in other contexts to mean something entirely different
  • The PartialFunction it receives is expected to return unit


--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang

Thanks for your reply, Tim!

On Feb 5, 2016 19:58, "Tim Harper" <[hidden email]> wrote:
>
>
>
> On Friday, February 5, 2016 at 6:08:37 AM UTC-7, √iktor Klang wrote:
>>
>>
>>> In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?
>>
>>
>> Because `a` is executed for its effect and not for its produced value.
>
>
> If the value is not used then the PartialFunction should be expected to return Unit. That way the compiler can at least say "hey pure expression here does nothing LOL are you sure?"

Again, the PF supplied is only executed for its side effects. If it is a pure PF then andThen is isomorphic to a no-op.

>
>
>>
>>> In which order will the above be executed?
>>
>> You didn't answer my question, Tim. :)
>
>
> It's indeterministic :)

Exactly, andThen makes it possible to make it not only deterministic in terms of which starts first, but the second only runs after the first finishes.

>
>>> future.map { r =>
>>>   try {
>>>     someStatefulThing()
>>>   } catch {
>>>     case e: Throwable =>
>>>       # completely ignore LOL
>>>   }
>>>   r
>>> }
>>> That will not execute the side effect if the Future failed.
>
>
> Fair point.
>
> So, there's inertia that there's use to the function (and while I can agree, I still believe the style of programming it encourages should be avoided at almost all costs), I think I could be satisfied with the following:
> The function is renamed to something else, since andThen is used in other contexts to mean something entirely different
> The PartialFunction it receives is expected to return unit

The method is completely voluntary to use, changing the signature only serves to break existing code, and renaming it serves little purpose IMO.

If you look at the signature you see that the result of the PF is not used, and if you read the scaladoc then you see what it's use-case is. Is that bad?

If you have suggestions for improving its documentation, I'd be more than happy to review them.

Cheers,
V

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

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Naftoli Gugenheim
In reply to this post by Viktor Klang


On Fri, Feb 5, 2016, 8:08 AM Viktor Klang <[hidden email]> wrote:
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).

Well, then you'll be delighted to know that they often also alias andThen as >> ;)

 

Why have a method "only for side effecting"?

You mean like `foreach`?

Weeelll....

You can use map (on collections) instead of foreach, except:
1. Foreach is more efficient since it doesn't have to create a new collection
2. For without yield desugars to foreach, so it needs to exist
 
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.


Okay: then it should be pf: PartialFunction[Try[T], Any]. The variance should allow it to accept a partial function with any return type. Or, PartialFunction[Try[T], _]. The point is, that kind of polymorphism generally tells you that the type is affecting something. It's not.

But, as Tim said, if it's only for side effects then it's not clear it should accept a PF with output other than Unit.
 
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?

That begs the question. :) Also re "the method" -- there are two points here (besides the question of type coherence). One is that similar functionality except somewhat more general is needed. The other is that the name makes it sound like it is that functionality. So once renaming is ruled out, the main question is really not about a specific method, but about functionality being available.

 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

Again that begs the question. What do you gain by having this restriction?
 
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang


On Sun, Feb 7, 2016 at 11:24 PM, Naftoli Gugenheim <[hidden email]> wrote:


On Fri, Feb 5, 2016, 8:08 AM Viktor Klang <[hidden email]> wrote:
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).

Well, then you'll be delighted to know that they often also alias andThen as >> ;)


Thanks buddy!
 
 

Why have a method "only for side effecting"?

You mean like `foreach`?

Weeelll....

You can use map (on collections) instead of foreach, except:
1. Foreach is more efficient since it doesn't have to create a new collection

same with onComplete vs andThen
 
2. For without yield desugars to foreach, so it needs to exist

Technically it could be a typeclass rather than something bolted onto the thing itself.
 
 
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.


Okay: then it should be pf: PartialFunction[Try[T], Any]. The variance should allow it to accept a partial function with any return type. Or, PartialFunction[Try[T], _]. The point is, that kind of polymorphism generally tells you that the type is affecting something. It's not.

Keeping the correct type around for as long as possible I think is a good thing. But I understand your argument.
 

But, as Tim said, if it's only for side effects then it's not clear it should accept a PF with output other than Unit.

I disagree. Having to wrap non-Unit-returning-PFs which you want to execute for their side-effect is ugly. (Assuming we think side-effects are non-ugly since we want to call a method which explicitly is for side-effects).
 
 
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?

That begs the question. :) Also re "the method" -- there are two points here (besides the question of type coherence). One is that similar functionality except somewhat more general is needed.

Wait, how would something be more general than the signature provided? :)
 
The other is that the name makes it sound like it is that functionality. So once renaming is ruled out, the main question is really not about a specific method, but about functionality being available.

I'm not sure I understand. Do you mean that "the method should not exist at all"? What would you have users write to achieve the same functionality as `andThen` currently does? (code example would be appreciated)
 

 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

Again that begs the question. What do you gain by having this restriction?

The original result is retained while ordering side-effects, which will have run to completion before the next starts?
 
 
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang
Hello? :(

On Tue, Feb 9, 2016 at 12:11 PM, Viktor Klang <[hidden email]> wrote:


On Sun, Feb 7, 2016 at 11:24 PM, Naftoli Gugenheim <[hidden email]> wrote:


On Fri, Feb 5, 2016, 8:08 AM Viktor Klang <[hidden email]> wrote:
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).

Well, then you'll be delighted to know that they often also alias andThen as >> ;)


Thanks buddy!
 
 

Why have a method "only for side effecting"?

You mean like `foreach`?

Weeelll....

You can use map (on collections) instead of foreach, except:
1. Foreach is more efficient since it doesn't have to create a new collection

same with onComplete vs andThen
 
2. For without yield desugars to foreach, so it needs to exist

Technically it could be a typeclass rather than something bolted onto the thing itself.
 
 
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.


Okay: then it should be pf: PartialFunction[Try[T], Any]. The variance should allow it to accept a partial function with any return type. Or, PartialFunction[Try[T], _]. The point is, that kind of polymorphism generally tells you that the type is affecting something. It's not.

Keeping the correct type around for as long as possible I think is a good thing. But I understand your argument.
 

But, as Tim said, if it's only for side effects then it's not clear it should accept a PF with output other than Unit.

I disagree. Having to wrap non-Unit-returning-PFs which you want to execute for their side-effect is ugly. (Assuming we think side-effects are non-ugly since we want to call a method which explicitly is for side-effects).
 
 
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?

That begs the question. :) Also re "the method" -- there are two points here (besides the question of type coherence). One is that similar functionality except somewhat more general is needed.

Wait, how would something be more general than the signature provided? :)
 
The other is that the name makes it sound like it is that functionality. So once renaming is ruled out, the main question is really not about a specific method, but about functionality being available.

I'm not sure I understand. Do you mean that "the method should not exist at all"? What would you have users write to achieve the same functionality as `andThen` currently does? (code example would be appreciated)
 

 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

Again that begs the question. What do you gain by having this restriction?

The original result is retained while ordering side-effects, which will have run to completion before the next starts?
 
 
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,



--
Cheers,



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Naftoli Gugenheim
In reply to this post by Viktor Klang


On Tue, Feb 9, 2016 at 6:11 AM Viktor Klang <[hidden email]> wrote:
On Sun, Feb 7, 2016 at 11:24 PM, Naftoli Gugenheim <[hidden email]> wrote:


On Fri, Feb 5, 2016, 8:08 AM Viktor Klang <[hidden email]> wrote:
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).

Well, then you'll be delighted to know that they often also alias andThen as >> ;)


Thanks buddy!
 
 

Why have a method "only for side effecting"?

You mean like `foreach`?

Weeelll....

You can use map (on collections) instead of foreach, except:
1. Foreach is more efficient since it doesn't have to create a new collection

same with onComplete vs andThen
 
2. For without yield desugars to foreach, so it needs to exist

Technically it could be a typeclass rather than something bolted onto the thing itself.

How does that change anything?
 
 
 
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.


Okay: then it should be pf: PartialFunction[Try[T], Any]. The variance should allow it to accept a partial function with any return type. Or, PartialFunction[Try[T], _]. The point is, that kind of polymorphism generally tells you that the type is affecting something. It's not.

Keeping the correct type around for as long as possible I think is a good thing. But I understand your argument.

But that's just it -- the type argument is not keeping it around any longer. It's just going into a black hole. It's precisely the principle just stated which is the reason why in some cases type parameters add value. But in this case it's only pretending -- it looks as if it's going to give you something, but then it disappoints. I think that's worse than being open up front that the type is not being kept around any longer.
 
 

But, as Tim said, if it's only for side effects then it's not clear it should accept a PF with output other than Unit.

I disagree. Having to wrap non-Unit-returning-PFs which you want to execute for their side-effect is ugly. (Assuming we think side-effects are non-ugly since we want to call a method which explicitly is for side-effects).

Well, perhaps the question is why you have a non-unit-returning thing that is *only* useful for its side effect. If it's returning a value, isn't that value useful? And if it's not, why is it returning it?
  
 
 
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?

That begs the question. :) Also re "the method" -- there are two points here (besides the question of type coherence). One is that similar functionality except somewhat more general is needed.

Wait, how would something be more general than the signature provided? :)

 
 
The other is that the name makes it sound like it is that functionality. So once renaming is ruled out, the main question is really not about a specific method, but about functionality being available.

I'm not sure I understand. Do you mean that "the method should not exist at all"? What would you have users write to achieve the same functionality as `andThen` currently does? (code example would be appreciated)

 
 

 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

Again that begs the question. What do you gain by having this restriction?

The original result is retained while ordering side-effects, which will have run to completion before the next starts?
 
 
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,



--
Cheers,

--
You received this message because you are subscribed to the Google Groups "scala-debate" group.
To unsubscribe from this group and stop receiving emails from it, send an email to [hidden email].
For more options, visit https://groups.google.com/d/optout.
Reply | Threaded
Open this post in threaded view
|

Re: Future.andThen should be deprecated

Viktor Klang


On Thu, Feb 18, 2016 at 4:20 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Tue, Feb 9, 2016 at 6:11 AM Viktor Klang <[hidden email]> wrote:
On Sun, Feb 7, 2016 at 11:24 PM, Naftoli Gugenheim <[hidden email]> wrote:


On Fri, Feb 5, 2016, 8:08 AM Viktor Klang <[hidden email]> wrote:
Naftoli,

Thanks for your emails, I'm sorry if my response sounds terse, but I'm writing this as I am talking to Dean Wampler and Jonas Bonér at a café, so I need to keep it short. :)

On Fri, Feb 5, 2016 at 12:05 AM, Naftoli Gugenheim <[hidden email]> wrote:


On Thu, Feb 4, 2016 at 4:58 PM Viktor Klang <[hidden email]> wrote:
On Thu, Feb 4, 2016 at 10:45 PM, Tim Harper <[hidden email]> wrote:
I think the behavior is tremendously surprising.

In what way is it surprising? Does it violate its documented contract?

No, it's name and type are confusing.

Not saying that you're wrong, but I'm not sure opinion can be treated as canon here.
Its sole use case is to be able to order side-effects, and no other method currently does that in a clean way, therefore it still has utility which is not easily replaced. I am not going to propose to rename it just for the sake of forcing people to do search-replaces in their codebases to avoid warnings.

If one is unhappy with the method, it is fully possible to add an implicit class which renames the andThen method to something else, and/or outlaw its usage throw an sbt-plugin (as with all methods one doesn't want to be used)
 

Most of monadic libraries (like slick DBIO) define andThen(b) as basically flatMap(_ => b)

Now, to me that's a huge waste of namespace (for the benefit provided).

Well, then you'll be delighted to know that they often also alias andThen as >> ;)


Thanks buddy!
 
 

Why have a method "only for side effecting"?

You mean like `foreach`?

Weeelll....

You can use map (on collections) instead of foreach, except:
1. Foreach is more efficient since it doesn't have to create a new collection

same with onComplete vs andThen
 
2. For without yield desugars to foreach, so it needs to exist

Technically it could be a typeclass rather than something bolted onto the thing itself.

How does that change anything?

It means that for those who want it, they can add it themselves, at no cost for the API or the sanity of others.
 
 
 
 
 

The signature is

def andThen[U](pf: PartialFunction[Try[T], U])(implicit executor: ExecutionContext): Future[T]

If U is not used anywhere, why have it? How is it different than def andThen(pf: PartialFunction[Try[T], Unit])?

To be able to use any PF which accepts a Try[T] input.


Okay: then it should be pf: PartialFunction[Try[T], Any]. The variance should allow it to accept a partial function with any return type. Or, PartialFunction[Try[T], _]. The point is, that kind of polymorphism generally tells you that the type is affecting something. It's not.

Keeping the correct type around for as long as possible I think is a good thing. But I understand your argument.

But that's just it -- the type argument is not keeping it around any longer.

Of course it does.
 
It's just going into a black hole. It's precisely the principle just stated which is the reason why in some cases type parameters add value. But in this case it's only pretending -- it looks as if it's going to give you something, but then it disappoints. I think that's worse than being open up front that the type is not being kept around any longer.

It *cannot* look like it's giving you something because that is not what the API signature says. :)
 
 
 

But, as Tim said, if it's only for side effects then it's not clear it should accept a PF with output other than Unit.

I disagree. Having to wrap non-Unit-returning-PFs which you want to execute for their side-effect is ugly. (Assuming we think side-effects are non-ugly since we want to call a method which explicitly is for side-effects).

Well, perhaps the question is why you have a non-unit-returning thing that is *only* useful for its side effect. If it's returning a value, isn't that value useful? And if it's not, why is it returning it?

Because if you already have a PF which is not returning Unit, you wouldn't want to have to wrap it to execute it?
 
  
 
 
 

If it's for side-effecting then why is it chainable?

Like it says in the documentation, to be able to order side effects.
 

If the results are run in sequence then why isn't the last value available?

Because that is not what the method does?

That begs the question. :) Also re "the method" -- there are two points here (besides the question of type coherence). One is that similar functionality except somewhat more general is needed.

Wait, how would something be more general than the signature provided? :)


Now, that committer seems like one of the good guys ;)
 
 
 
The other is that the name makes it sound like it is that functionality. So once renaming is ruled out, the main question is really not about a specific method, but about functionality being available.

I'm not sure I understand. Do you mean that "the method should not exist at all"? What would you have users write to achieve the same functionality as `andThen` currently does? (code example would be appreciated)

 

Exactly, and to get all that correct for someone new is *not* trivial. :)
 
 

 
In f.andThen(a).andThen(b), if b will only run when a completes then why can't it see what value it produced?

Because `a` is executed for its effect and not for its produced value.

Again that begs the question. What do you gain by having this restriction?

The original result is retained while ordering side-effects, which will have run to completion before the next starts?
 
 
 

If the reason it returns a Future[T] and not a Future[U] is just in case you want to be able to access `f`'s T if `a` fails so there is no U (does not sound like a very general use case), a better solution would be more general methods. Some examples of more general methods that would be nice to have:
  • Something like flatMap that whose function takes a Try[T] instead of a T
 
  • Something like map except Try[T] => Try[U]
 
  • A fold method that unlike transform does not require the failure case to remain a failure
  • A simple way to lift a Future[A] into a successful Future[Try[A]]


 


 
That it returns a Future at all leads one to believe that "oh it's probably a future after the andThen completes".

Yes, that is what it does.

From the ScalaDoc:

Applies the side-effecting function to the result of this future, and returns a new future with the result of this future.

This method allows one to enforce that the callbacks are executed in a specified order.

Note that if one of the chained andThen callbacks throws an exception, that exception is not propagated to the subsequent andThencallbacks. Instead, the subsequent andThen callbacks are given the original value of this future.

The following example prints out 5:

val f = Future { 5 }
f andThen {
  case r => sys.error("runtime exception")
} andThen {
  case Failure(t) => println(t)
  case Success(v) => println(v)
}
 

I think `Future.onComplete` is wholly sufficient to modify side effecting code.

It isn't. See example later in this email.
 
Also, `Future.andThen` leads to further confusion because implies concatenation because of the `Function1.andThen` function.


Yes, there is a name clash with reverse-order function composition.
 
I'd recommend that `Future.andThen` be deprecated. If people need to write side-effecting code, it's much clearer for them to use onComplete, which returns Unit and leaves little question as to it's affect on the value of the original future.

future.onComplete { case _ => scheduleLaunchOfMissiles() }
future.onComplete { case _ => cancelScheduledLaunchOfMissiles() }

In which order will the above be executed?
 

Tim

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



--
Cheers,

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



--
Cheers,



--
Cheers,



--
Cheers,

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