--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Victor,Thanks for your answer. I'm not sure If I understand you correct?In the lib there is code which is implemented by us and which gets called by the user and there is code which must be implemented by the user and which gets called by the lib.
Best regards,ChristianAm Montag, 18. Mai 2015 16:55:26 UTC+2 schrieb √iktor Klang:Hi Christian,Who is responsible for the execution of the logic: the caller or the creator if the context? (i.e. pass into constructor or pass into each method)On Mon, May 18, 2015 at 2:58 PM, Christian Kaps <kaps.ch...@gmail.com> wrote:Hi,--currently in the Silhouette authentication library, we have hard-coded the global Play Framework ExecutionContext all over the code. Now we would like to remove this hard-coded imports and allow the user to specify its own ExecutionContext. But we are struggling with the best approach. Currently we have a pull request which adds an implicit execution context to every method that returns a Future. But we are not sure if this is the right approach. Can someone give us an advice how to choose the best strategy? Any help would be highly appreciated!Best regards,Christian
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
--Cheers,√--
You received this message because you are subscribed to the Google Groups "scala-user" group.
To unsubscribe from this group and stop receiving emails from it, send an email to scala-user+...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
Hi Victor,
> It's about division of responsibility. I.e. who should control the execution at which point?
I think that's the point we struggle with! Is there a general rule who should control the execution at which point?I hope that doesn't sound dumb (o;
I am not convinced this is really the right question.
Generally the need to provide an implicit EC in the API is kind of an anti pattern because its a leak of implementation detail, its about how the algorithm works not what its meant to do.
A library might very well never have concurrency primitives in its API definition and yet be exposing the need for an execution context either via constructor or individual methods.
But from the application using the library perspective the few cases that need to pass in custom ECs really need to and the library might be worthless if that isn't possible.
There is a third option, which is that you import the Default or your own EC and never expose it to the outside API at all. That to me is the more important question and its a very real option as well.
Its really hard to choose between the ways in which EC is injected because it requires you to predict how the library will be used and how application logic will call construction and library methods and what EC is available at these points.
If you put it in the constructor and your object lives for the life of the application then the application has to have that ready before your library is called. However putting it into the call sites means that dependency is required in all the classes that use the library, but it can be binded to later and dynamically. The flexibility hurts on the usability of the API and the amount of extrinsic pain your cause the users of your library.I think the topic is a bit more complicated and nuanced and there is a real issue of API design as I definitely see a third option (hide it completely) and why you would want to do that. The constant pollution of Scala library APIs with ExecutionContext's I find irritating, at method call site more than constructor based. It forces a lot of external dependency outside of the library and forces you to program in a very particular way. Its not an easy choice what to do and the way a lot of library's do this (spray can!) I don't think is all that usable.
My 2 cents:- When the library is completely asynchronous and can work with any EC, I'd expose it via constructor.- When some method are kinda blocking, I'd expose the EC at method definition.But I agree with Paul, it is really polluting the API.
Especially when I know that the library itself is completely asynchronous, I'd like to have a way to say "choose whatever EC you want, I do not care".
In a way it boils down to a problem with implicits in general. The same issue could occur with other types as well.
Actually I think Haoyi had something that will fill in the implicit parameters for you.
But what exactly do you mean by "polluting the API"? Is it conceptually wrong to say that the code is parameterized by it? Is it the repetitive typing? Line noise reading the code? The API docs? The autocomplete choices?
(I guess the answer well be multiple, but which ones?)
As an aside, as far as asynchronous code, IIUC scalaz Tasks don't have this problem, since they don't run until you start them explicitly, and so that is the point at which you need to specify the execution characteristics, not when you're creating or composing them.
implicit class PimpMyAtomicReference[A](val self: AtomicReference[A]) extends AnyVal {
import self._
def asyncCasSet[B](
f: A => Future[A]
)(implicit
ec:ExecutionContext
) : Future[CasSet[A]] = {
def loop() : Future[CasSet[A]] = {
val current = get
for {
next <- f(current)
result <- {
if (compareAndSet(current, next) == false) {
loop()
} else {
CasSet(current, next).future
}
}
} yield result
}
loop()
}
}
trait PersonService extends Contract {
import PersonService._
// No constructor code or initialized vals
/**
* Create a new person. Fails if id exists.
* @param id id of person
* @param name name of person
* @param age age of person
* @return if successful unit
*/
def create(id: Int, name: String, age: Int) : Future[PassOrFail]
class PersonServiceImpl()(implicit ec: ExecutionContext) extends PersonService {
override def create(id: Int, name: String, age: Int) = ???
/**
* A mix-in trait for a component that has an execution context
*/
trait HasExecutionContext {
implicit def executionContext: ExecutionContext
}
trait AuthServiceRpcActions extends
AuthService with
HasExecutionContext with
Logging {
case class Session()(implicit
val executionContext: ExecutionContext,
val loggingContext: LoggingContext,
users: userDataDao.Session,
groups: groupDataDao.Session
) extends super.Session with HasExecutionContext with HasLoggingContext {