My new open source framework Flint is pure Swift and involves splitting your code into small actions that when performed are passed a single input and a presenter object.
What is cool about this is that we use Swift’s associated types to allow action implementations to specify the type of the input and presenter. Here’s an example:
In the application, you perform the action via a generic type, the StaticActionBinding
, using this function:
This all works great. Your binding has a perform(using:with:completion:)
function that only supports the correct types the Action expects. However if you have an action that does not need an input or presenter, you have to use special types Flint defines called NoInput
and NoPresenter
to satisfy the associated types:
This works well enough, but invoking those actions would look like this:
It’s pretty ugly. Thanks to a nudge from @hishnash I looked into how we could eliminate the arguments that are not needed in those cases. I originally tried overloading the perform
function with generic functions constrained on InputType
and PresenterType
but… you can’t do that.
It turns out that since Swift 4 the addition of conditional conformances can help us. We can overload the perform
function and constrain each version to specific types for InputType
and PresenterType
:
(See full source: StaticActionBinding.swift)
Conditional conformances are only possible in extensions, and because the conditions vary for each version of the perform
method we want, we needed three extensions as shown above.
However it is worth the effort. Invoking these kinds of actions is now much nicer:
That is pretty great. While generics and associated types can be a real pain to use, it’s important to celebrate these great little wins where something quite advanced is possible in a type-safe way with very little effort.