Type Injection in swift

A friend of mine who is new swift (but who has overwhelming experience in android using both java and kotlin) approached me recently with a question/concern: why aren’t there abstract classes in swift? His comment on justifying the need of abstract class was this: I want to be able to flash out most of the functionality in my class but there’s some minor thing that I want to leave abstract — and defined by subclasses. Here’s what I told him.

Abstract classes used to be one of the major advantages of modern OOP languages like c++ and java. It makes it possible distribute functionality implementations between classes in inheritance hierarchy. I remember mimicking that design in Objective-C by providing actual method implementation with contents like

- (void)abstractMethod {
@throw [NSException exceptionWithName:NSInvalidArgumentException
reason:[NSString stringWithFormat:@”%s must be overridden in a subclass/category”, __PRETTY_FUNCTION__]
userInfo:nil]
}

since Objective-C doesn’t have nice abstract method support.
However, this also encourages developers to introduce more levels in inheritance hierarchy, which (history proves) doesn’t scale and introduces unwanted strong coupling.

Compose all the things!

New type-oriented languages, like swift, encourages developers to leverage composition more in favour of inheritance. In my friend’s example he had a base StepViewController that did all the heavy work but had some definitions abstracted away like this StepViewController

// this is abstract method
open func render() -> [TableSection] {
return [] //
}

and there was another SignUpViewController that implemented that one particular method:

override func render() -> [TableSection] {
return [
TableSection(rows: [
firstNameCell(),
lastNameCell(),
businessCell(),
emailCell(),
passwordCell()
])
]
}

This could be re-factored in a way so it doesn’t use inheritance for this kind of abstraction. We could leverage dependency injection by moving this render() function into a dependency:

protocol Renderer {
func render() -> [TableSection]
}

and then make StepViewController use it as a type of a property:

class StepViewController {

var renderer: Renderer
 private func render() -> [TableSection] {
return renderer.render()
}
}

Notice how I changed declaration of render() function in StepViewController — it’s now private as it’s not exposed externally anymore and only needed to be used internally.
There’s one thing missing though: injection. We need a way to provide dependency at StepViewController creation — through constructor. It’s going to be challenging to make clean with subclasses of UIViewController though. First, we would need to disable all UIViewController’s provided constructors:

@available(iOS, unavailable)
init() { fatalError() }
@available(iOS, unavailable)
override init(nibName nibNameOrNil: String?, bundle nibBundleOrNil: Bundle?) { fatalError() }
@available(iOS, unavailable)
required init?(coder aDecoder: NSCoder) { fatalError() }

And then we’ll provide required constructor taking dependency:

required init(dependency: Renderer) {
self.renderer = dependency
super.init(nibName: nil, bundle: nil)
}

This seems to be enough: it’s now impossible to create and instance of StepViewController without a renderer dependency. Going back to my friends example, he wanted to define abstraction details in subtype — so he can use that subtype as elsewhere. Ok, here it is:

class SignUpViewController: StepViewController {
convenience init() {
super.init(dependency: SignUpRenderer())
}
}

That won’t work though, because we already disabled that kind of `init`. The solution would be using static function instead of constructor, like:

static func instantiate() -> SignUpViewController {
return SignUpViewController(dependency: SignUpRenderer())
}

This introduces a couple of things: 
1. This kind of construction if type-bound, e.g. non-virtual (and if you do want to make it virtual you’d have to add static instantiate to base class with empty implementation, kind of what we wanted to avoid)
2. It’s possible to create instance of SignUpViewController using constructor with dependency that might not be what SignUpViewController wants it to be. What if we wanted to lock type of dependency to the type of it’s user?

Type injection

When we want to lock type of dependency to the type of it’s user — we need to be looking at type parameterization, e.g. generics. Turns out it solves all my concerns expressed earlier.
Let’s make StepViewController generic first:

class StepViewController<RendererType: Renderer>: UIViewController {
var renderer: RendererType
init() {
renderer = RendererType()
}
}

Then, making SignUpViewController to lock into particular Renderer is trivial:

typealias SignupViewController = StepViewController<StepHeaderRenderer>

Note, that it’s effectively injected type and this type can be accessible anywhere in code of base StepViewController — including all it’s designated constructors. We can still have dependency instance injection by using all above techniques with disabling existing constructors and providing our own. However, now we could guarantee that dependency type is a designated one:

extension StepViewController
init(depedency: RendererType) {
self.init()
self.renderer = depedency
}
}