-
Notifications
You must be signed in to change notification settings - Fork 13
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Consolidate event handling into Listener type. #245
Conversation
@@ -0,0 +1,41 @@ | |||
package com.instacart.formula | |||
|
|||
class BoundStream<Message>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Renamed from Update
to BoundStream
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Moving this into #246
5c4aee3
to
943b092
Compare
/** | ||
* Formula uses Listener callbacks to pass events. | ||
*/ | ||
fun interface Listener<Event> : (Event) -> Unit { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Still debating what would be the right name for this.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I prefer Listener
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Another option would be Handler
. I don't have a strong preference, just throwing it out there to see what other people think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, I've also thought about Handler
though I didn't like its associations with android.Handler
@@ -0,0 +1,30 @@ | |||
package com.instacart.formula | |||
|
|||
interface TransitionContext { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Not yet sure about moving this out.
* and/or [Effects] that should be performed. You can return [Transition.None] if nothing | ||
* should happen. | ||
*/ | ||
fun interface Update<State, Event> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm wondering how to better unify this with the Transition
type. Maybe this should be changed to
fun interface Transition<State, Event> {
sealed class Result {
/**
* Stateful transition.
*
* @param state New state
* @param effects Optional effects such as parent callbacks, logging, db writes,
* network requests, etc.
*/
data class Stateful<State>(val state: State, override val effects: Effects? = null) : Result<State>()
/**
* Only effects are emitted as part of this transition
*
* @param effects Effects such as parent callbacks, logging, db writes, network requests, etc.
*/
data class OnlyEffects(override val effects: Effects) : Result<Nothing>()
/**
* Nothing happens in this transition.
*/
object None : Result<Nothing>() {
override val effects: Effects? = null
}
}
fun TransitionContext.create(event: Event): Result<State>
}
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, having an Update
that produces a Transition
is a bit confusing, would be better to not have that extra name I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does Update
and Update.Result
or Transition
and Transition.Result
seem better? On one hand, Update
corresponds to MVU
naming, however many folks like the name Transition
(including me).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm moving this change out of this PR.
import com.instacart.formula.Update | ||
|
||
@PublishedApi | ||
internal class TransitionDispatcher<State>( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was called TransitionCallbackWrapper
previously
} | ||
|
||
// TODO: naming UpdateType as transition seems weird. We need to resolve these two types. | ||
fun <Event> dispatch(transition: Update<State, Event>, event: Event) { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: fix this once we resolve naming for Update
children?.forEachValue { it.markAsTerminated() } | ||
} | ||
|
||
override fun performTerminationSideEffects() { | ||
children?.forEachValue { it.performTerminationSideEffects() } | ||
updateManager.terminate() | ||
callbacks.disableAll() |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The reason I'm moving this from markAsTerminated
to performTerminationSideEffects
is to allow termination side-effects to execute.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This was needed for https://github.com/instacart/formula/pull/245/files#r719839477
a159563
to
c39f88b
Compare
JaCoCo Code Coverage 79.03% ✅
Generated by 🚫 Danger |
c39f88b
to
3b38fad
Compare
* Note: this class is not a data class because equality is based on instance and not [key]. | ||
*/ | ||
@PublishedApi | ||
internal class CallbackImpl<State, Event>(internal var key: Any) : Listener<Event> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: this should be renamed to ListenerImpl
or Listener
should be renamed to Callback
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add this as a comment to this class?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Most likely, I'm going to rename this before merging the PR.
3b38fad
to
0bc9a30
Compare
} | ||
|
||
val key = JoinedKey(stream.key(), transition::class) | ||
val callback = formulaContext.onEvent(key, transition) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This now delegates to onEvent
to create the Stream
listener/callback. This was made possible, by https://github.com/instacart/formula/pull/245/files#r719810293
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM 👍🏼
*/ | ||
inline fun <UIEvent> onEvent( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Any reason we migrated off inline
for all functions here?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Previously, we were creating another function inside of here and cross-inlining the transition
function to save an extra object allocation. I've restructured this, so inline isn't needed anymore.
} | ||
|
||
/** | ||
* Utility function used to specific |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
INcomplete comment?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Updated
* Note: this class is not a data class because equality is based on instance and not [key]. | ||
*/ | ||
@PublishedApi | ||
internal class CallbackImpl<State, Event>(internal var key: Any) : Listener<Event> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Maybe add this as a comment to this class?
@@ -17,7 +17,7 @@ class EventCallbackFormula : Formula<Unit, String, EventCallbackFormula.Output> | |||
return Evaluation( | |||
output = Output( | |||
state = state, | |||
changeState = context.onEvent { newState -> | |||
changeState = context.onEvent<String> { newState -> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This actually adds up to the code readability.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Do you mean improves code readability?
* and/or [Effects] that should be performed. You can return [Transition.None] if nothing | ||
* should happen. | ||
*/ | ||
fun interface Update<State, Event> { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yeah, having an Update
that produces a Transition
is a bit confusing, would be better to not have that extra name I think.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good, I like the changes.
Hey folks, thank you for your initial review 💯 To reduce the scope of this PR, I've moved some changes such as |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM, just one question.
@@ -17,7 +18,7 @@ class KeyUsingListFormula : | |||
|
|||
data class ItemRenderModel( | |||
val item: String, | |||
val onDeleteSelected: () -> Unit | |||
val onDeleteSelected: Listener<Unit> |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Does this change mean we need to type our callbacks as Listener
in RenderModels, or is this change specific to these formulas?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
When using onEvent
you will need to type to Listener
type (or (Event) -> Unit
). For now, there still exists callback
and eventCallback
which support old style.
What
Listener
type (maybe should call itCallback
instead). This replaces() -> Unit
and(Event) -> Unit
TransitionCallbackWrapper
toTransitionDispatcher
.