Created
September 28, 2019 22:22
-
-
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)
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// 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