Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save masonmark/967ec16161d6e0b26e146f32c2f35898 to your computer and use it in GitHub Desktop.
Save masonmark/967ec16161d6e0b26e146f32c2f35898 to your computer and use it in GitHub Desktop.
One way to let a subclass inherit a method referencing its own type in Swift (slightly improved)
// Mason 2019-09-29: This is one way to allow subclasses to inherit a
// method with a parameter whose type refers to the actual subclass type
// (and not the parent class's type).
//
// One purpose here is to define a base class, that can have various
// subclasses, and enable all of the subclasses to inherit a class method
// named configure(), which creates an instance of the subclass and then
// configures the instance and its various subclass-specific properties.
//
// The improvements are based on feedback in this thread on the Swift forum:
//
// https://forums.swift.org/t/how-to-let-subclass-inherit-a-method-referencing-its-own-type/29350
//
// This is a simplified and improved revision to my first attempt:
//
// https://gist.github.com/masonmark/9036c1767ffef24c15e450478861cdde
protocol Configurable: AnyObject {
init()
}
extension Configurable {
static func configure( _ configurator: (Self) -> Void) -> Self {
let result = Self.init()
configurator(result)
return result
}
}
/// Classes which conform to `Configurable` must also implement (or
/// inherit from another class that implements) a `required init()`
/// initializer to satisfy the compiler.
class Person: Configurable {
/// This required initializer must be present to satisfy the compiler.
required init() {}
var name = "Alice"
var age = 0
var bio: String {
"My name is \(name), and I am a \(Self.self). I am \(age) years old."
}
}
class FireFighter: Person {
var helmetSize: Int?
var hasLicenseToDriveFireEngine = false
}
class PoliceOfficer: Person {
var badgeNumber: String = "0000000"
}
let rand = Person.configure { rand in
rand.age = 117
rand.name = "Rand"
}
let jane = PoliceOfficer.configure() { jane in
jane.name = "Jane"
jane.age = 42
jane.badgeNumber = "8675309"
}
func configureBiff(biff: FireFighter) {
biff.hasLicenseToDriveFireEngine = true;
biff.helmetSize = 15
biff.age = 21
biff.name = "Biff Wigginberger Jr."
}
// Pass a function to `configure()` instead of doing it inline:
let biff = FireFighter.configure(configureBiff)
print(rand.bio)
print(jane.bio)
print(biff.bio)
// prints:
// My name is Rand, and I am a Person. I am 117 years old.
// My name is Jane, and I am a PoliceOfficer. I am 42 years old.
// My name is Biff Wigginberger Jr., and I am a FireFighter. I am 21 years old.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment