Add this suggestion to a batch that can be applied as a single commit.
This suggestion is invalid because no changes were made to the code.
Suggestions cannot be applied while the pull request is closed.
Suggestions cannot be applied while viewing a subset of changes.
Only one suggestion per line can be applied in a batch.
Add this suggestion to a batch that can be applied as a single commit.
Applying suggestions on deleted lines is not supported.
You must change the existing code in this line in order to create a valid suggestion.
Outdated suggestions cannot be applied.
This suggestion has been applied or marked resolved.
Suggestions cannot be applied from pending reviews.
Suggestions cannot be applied on multi-line comments.
Suggestions cannot be applied while the pull request is queued to merge.
Suggestion cannot be applied right now. Please check back later.
This PR introduces convenience classes for broadcasting to actors and type checking the responses.
Typechecking
Although having a typed response provides a certain level of robustness in the communication, it is often the case when using "ask" that we expect a specific (sub-)type of a response.
The
Typechecking
andTypecheckSyntax
implicits offer convenience methods to do this dynamic type checking usingClassTag
.More specifically,
TypecheckFOps
provides methods to typecheck any effectful resultF[R]
. If the typecheck succeeds, we return the result safely casted to the checked type. Each of the available methods offers a different way of reporting a failed typecheck, using anOption
(typecheckOpt
) an alternative result in anEitherT
(typecheckOr
andtypecheckOrF
) or raise an error (typecheck
).Finally,
TypecheckActorOps
offers an "ask" with a response of an expected type (?>
). We also provide a version of this ask where the response is first pre-processed by a given function before the type check (?>>
). We have found this to be useful if you want to pre-process responses with specific semantics, e.g. responses corresponding to errors which wouldn't typecheck.Example:
Note here that
plainResponse
is of typeResponse
whereastypedResponse
is of typeYes
and needs no further checking. If the actor were to replyNo
(e.g. if we usedactor ?>[Yes] Water
), we would get aTypecheckException
at that point.Broadcast
Broadcasting is essentially a
traverse
orparTraverse
over a list of actors, sending the same message to all of them. The newly introduced class and syntax offers some convenience in the following ways:!
or?
directly to a traversable collection of actors.map
/flatMap
/mapFilter
each response.What is important here is to note that all the mapping and filtering methods are applied on each response individually as soon as we get them (in parallel when using
.parallel
). One could achieve the same effect by traversing the resulting list of responses. That would mean a second traversal of that list with an associated O(n) cost (even if that is often small).Example usage is taken from
com.suprnation.actor.broadcast.TreenodeActor
in the unit tests:Explanation:
children
carries a list of actor refs. We can use?
to broadcastPing
to all of them..mapping
method allows us to apply a partial mapping function and handle some of the responses. In this case, we useFail
as an error response and raise a specific exception if we receive it..expecting
method specifies the type of response we are expecting (otherwise we get aTypecheckException
)..parallel
method executes the broadcast in parallel and yields the collection of responses..map
uses.combineAll
to compose all of the responses together.One benefit of using these methods and particularly
expecting
here is that it could be the case that theResponse
type is not a monoid so we wouldn't be able to usecombineAll
directly. Here the mapping and type checking of the responses results in a collection ofPong
which is a monoid, so we can usecombineAll
immediately. All of this is accomplished in a single, declarative chain of methods.I tried many different approaches to setting this up and all of them felt somewhat opinionated and with different pros and cons. I ended up with this one, which is not perfect, but quite convenient at least for the purposes described here.
All feedback welcome!