Skip to content
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

[RFC] [DNM] SideEffect as Type #1182

Closed
wants to merge 4 commits into from

Conversation

dhavalshreyas
Copy link
Contributor

@dhavalshreyas dhavalshreyas commented May 27, 2020

Context

In #1174, we introduce the sideEffect API on RenderContext:

runSideEffect(key: AnyHashable, action: (Lifetime) -> Void)

action is executed the first time a key is encountered and Lifetime.onEnded is called after it's no longer needed.

Example usage:

sink = context.makeSink(Action.self)
context.runSideEffect("entity-" + entityId) { lifetime in 
  fetchEntity(entityId) { sink.send(.gotEntity) }
}

Proposal

Make SideEffect a type:

protocol SideEffect: Hashable {
  func run(sink: Sink<Action>) -> Lifetime
}

and the API becomes:

func run<S: SideEffect>(sideEffect: S)

Why?

Harder to mess-up

The Hashable contract implies that the hashValue will be calculated based on hashing all the contents of the object (SideEffect). If the hashValues are the same, we then compare the two objects to make sure they're the same. This contract gives us a strong guarantee that the block of work that will be executed by the SideEffect will be the same.

If we instead put the responsibility on the consumer of the API to formulate the right key, we will be unnecessarily burdening the caller to carefully generate the right key and the impact of doing this incorrectly will be subtle.

In other words, if we want the key to represent the same action AND the action is a function of (a, b, c) I believe that the the key should be f(a, b, c)

Flexible

Making SideEffect a protocol (instead of having the key and an independent action closure) will make this more flexible. We will then be able to get any of the Workers to conform to the SideEffect. (Instead of having an intermediate Workflow to do the runSideEffect call.)

@dhavalshreyas
Copy link
Contributor Author

dhavalshreyas commented May 27, 2020

Actually, thinking through this..since we'll be using the sink to dispatch changes - this model might not make as much sense. :(

Back to the drawing board.

This has now been addressed.

@dhavalshreyas dhavalshreyas reopened this May 27, 2020
@JustinDSN
Copy link
Contributor

Why did we close / reopen?

Did something change?

Comment on lines +17 to +21
public protocol SideEffect: Hashable {
associatedtype Action: WorkflowAction

func run(sink: Sink<Action>) -> Lifetime
}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Squinting, this looks a lot like Worker.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It pretty much is - except we're moving the ReactiveSwift specific stuff out of Worker. So instead of it returning SignalProducer<Output>, we'll be passing in a Sink and use an internal concept for Lifetime instead.

Oh, we're also adding a hash value to it.

@dhavalshreyas
Copy link
Contributor Author

Why did we close / reopen?

Did something change?

Yes, we're now passing the sink on run.

@dhavalshreyas
Copy link
Contributor Author

This was discussed in #1021, the team has decided to stick with the API as-designed.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants