Swift: how to support "template method" design pattern (since Swift doesn't have protected)? - swift

Traditionally in the "template method" pattern, a base class implements some algorithms and defers to derived classes for specific behavior. This works well in languages like C++/C#/Java because you can use "protected" on those methods to hide them from the callers but keep it visible for derived classes. For example, in the GoF book, you have something like:
class Application
{
void CreateDocument() { ..., this->DoCreateDocument() }
protected void DoCreateDocument() { } // override for custom behavior
}
This keeps the public interface for Application clean. In Swift, because you cannot use protected, the public interface is not clean. I do not want users of Application to see DoCreateDocument.
So I'm trying another method, which instead of using methods for DoCreateDocument, I'm trying to define a closure and use "functor" patterns.
class Application
{
typealias ActionFunc = () -> ()
private let doCreateDocument : ActionFunc
init(a : ActionFunc) { self.doCreateDocument = a }
func CreateDocument() {
self.doCreateDocument()
}
}
So this class looks good - the public interface is clean. However, it's impossible to actually use this.
The obvious approach is using a derived class:
class DoApplication : Application
{
init() {
super.init(
a : {
// This would work, but you cannot use self here!
self. // anything with self. is an error
})
}
}
The problem with this approach is that in the initializer, you cannot pass a closure to super.init that uses self. I get the error self used before super.init.
That basically makes it useless because you cannot access any state variables.
However, if you don't initialize doCreateDocument in the init, you need to expose a setter of some sorts - again, the lack of protected means that the setter is on the public API. Yuck.
So is there any way to cleanly implement the template pattern that keeps the interface clean?

I know this is an ugly hack, but it works.
class DoApplication: Application {
init() {
var doCreateDocument: (Application.ActionFunc)!
super.init(a: { doCreateDocument() })
doCreateDocument = { [unowned self] in
self.foo()
}
}
func foo() {
println("DoApplication.foo");
}
}
Alternatively, you can pass self to doCreateDocument:
class Application {
typealias ActionFunc = (Application) -> ()
private let doCreateDocument : ActionFunc
init(a : ActionFunc) { self.doCreateDocument = a }
func CreateDocument() {
self.doCreateDocument(self)
}
}
class DoApplication : Application {
init() {
super.init(a : { _self in
let _self = _self as! DoApplication
_self.foo()
})
}
func foo() {
println("DoApplication.foo");
}
}

Related

How to prevent subclasses from inheriting super class's static method in Swift?

In the case of the following code, it is possible to call both Base.f() and Sub.f() because the sub class inherits its parent class's static method.
But I want to use only Base.f(), and don't want to use Sub.f() in my code.
Base.f() and Sub.f() do the same thing in the following case.
If both Base.f() and Sub.f() are used in my code, it just makes my code complex and difficult to find the places where f() are used.
Is it possible to tell swift to generate a compile error if Sub.f() is used?
Or, is there an alternative way to do it other than to define f() as a global function?
class Base {
static func f() {
print("hello world")
}
}
class Sub: Base {
}
Base.f()
// hello world
Sub.f()
// hello world
EDIT
More meaningful example than printing "hello world".
In the following case, I don't want to call it with Sub1.findSubclassByType("sub2") because Sub1 finding a subclass sounds funny.
So, I want to always call it with Base.findSubclassByType("sub2").
Maybe, defining findSubclassByType(type) in Base is a wrong design of a class? (Although, it is convenient that Xcode suggests findSubclassByType(type) when I type Base..)
What should I do?
class Base {
static func findSubclassByType(_ type: String) -> Base {
// find and return a subclass
if type == "sub1" {
return Sub1()
} else if type == "sub2" {
return Sub2()
} else {
fatalError("no sub class")
}
}
}
class Sub1: Base {
}
class Sub2: Base {
}
The comments of my question contains many good answers:
there is no dedicated swift feature to prevent subclasses from inheriting super class static methods.
move static functions to a new (final) class or struct
use class instead of static (=final class) and override the class method and add #available(*, unavailable) to it.
use Lint tools
I think the easiest way is to create a new (final) class for static methods which do not depend on subclasses, though, that sacrifices code completion feature a little.
I hope someday Swift will introduce #noInherit static func attribute.
EDIT
I found another way to restrict the way to call a static method in runtime:
class Base {
static func f() {
if Self.self != Base.self {
fatalError("don't call from subclass: " + String(describing: Self.self))
}
print("hello world")
}
}
note: The disadvantage of the EDIT is that it is checked only in runtime. The benefit of it is that you need only 3 lines and you don't need to override the static method in all subclasses. But this way should be used only when you have confident that checking in runtime is enough and safe for your app.
What you're precisely asking is impossible, because the only public/internal members that are not inherited by subclasses are initializers—and only when a subclass defines its own designated initializer, without implementations of all of its superclass's initializers.
So, to abuse that capability, you can use failable initializers when you don't need a return value…
class Base {
init() { }
#discardableResult init?(printingHelloWorld: Void) {
print("hello world")
return nil
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
Base(printingHelloWorld: ())
…or throwing initializers, when you do.
class Base {
init() { }
struct Error: Swift.Error {
let payload: String
}
init(returningAPayload: #autoclosure () -> Never) throws {
throw Error(payload: "💰")
}
}
class Sub: Base {
init(_: Any) {
super.init()
}
}
extension Never {
init() { fatalError() }
}
do {
try Base(returningAPayload: .init())
} catch {
(error as! Base.Error).payload
}
I advise against any of this, and subclassing in general.

How can you enforce a subclass of an NSObject-based base class override a class-level variable?

Completely rewriting this question yet again to hopefully put the focus on the issue I'm trying to solve.
We have the following class that, due to an external framework outside of our control, requires us to implement ObjCProtocolRequiringBla, like so...
class FooBase : NSObject, ObjCProtocolRequiringBla {
class var possibleValues:[String] {
// Note: Use preconditionFailure, not fatalError for things like this.
// At runtime, they both halt execution, but precondition(Failure)
// only logs the message for debug builds. Additionally,
// in debug builds it pauses in a debuggable state rather than crash.
preconditionFailure("You must override possibleValues")
}
// This satisfies the objective-c protocol requirement
final func getBla() -> Bla {
let subclassSpecificValues = type(of:self).possibleValues
return Bla(withValues:subclassSpecificValues)
}
}
class FooA : FooBase
override class var possibleValues:[String] {
return [
"Value A1",
"Value A2",
"Value A3"
]
}
}
class FooB : FooBase
override class var possibleValues:[String] {
return [
"Value B1",
"Value B2",
"Value B3",
"Value B4"
]
}
}
As you can see, possibleValues is used in the implementation of getBla(). Additionally, it has to be common to all instances of that particular subclass, hence being a class variable and not an instance variable. This is because in another place in the code, we have to retrieve all possible values across all subclasses, like so...
static func getAllPossibleValues:[String] {
return [
FooA.possibleValues,
FooB.possibleValues
].flatMap { $0 }
}
What I'm trying to figure out how to do is make the compiler complain if a subclass of FooBase does not implement possibleValues.
In other words, how can we make this report a compile-time error:
class FooC : FooBase
// Doesn't override class var possibleValues
}
Currently the only way I know of is the above, defining it in the base class with a preconditionFailure or similar, but that's a runtime check, not compile-time so it's not the best solution.
What I'm trying to figure out how to do is make the compiler complain if a subclass of FooBase does not implement possibleValues.
You can't. You can make something like possibleValues a protocol requirement and try to adopt that protocol, obviously, but if FooBase itself implements possibleValues you cannot get the compiler to complain if a subclass fails to override it. This is not a silly idea and there are probably computer languages that give you a way to do it, but Swift is not such a language. That's why the runtime solution is the best you can hope for, and that's the standard pattern, as you can see if you look at something like UIPopoverBackgroundView.
You could solve this by replacing your FooBase class with a protocol that extends NSObjectProtocol. This will force any class implementing your protocol to having to be a subclass of NSObject and also implement the properties and methods you want.
protocol foo: NSObjectProtocol {
var someProp: String {get set}
func someFunc() -> Void
}
To have the protocol being used from Objective-C one can use the #objc annotation, this works at least for simple scenarios such as sending an selector, #selector(), as a parameter.
#objc protocol foo: NSObjectProtocol {
var someProp: String {get set}
func someFunc() -> Void
}
With that the following code worked fine
class fooClass: NSObject, foo {
var someProp: String
init(someProp: String) {
self.someProp = someProp
}
func someFunc() {
print("In someFunc with property: \(someProp)")
}
func timeIt() {
let timer = Timer.scheduledTimer(timeInterval: 0,
target: self, selector: #selector(someFunc), userInfo: nil, repeats: false)
print("timer created")
timer.fire()
}
}
func main() {
let f = fooClass(someProp: "test")
f.timeIt()
}
main()
Something along these lines, perhaps? I didn't hammer out every last detail, but I think this covers a lot of your programming problem. If you'd like to discuss it further, let's start a chatroom rather than continuing to post endless comments here.
// Just to get it to compile
class Bla { init(withValues: [String]) {} }
protocol ObjCProtocolRequiringBla {}
class FooContainer : ObjCProtocolRequiringBla {
fileprivate var fooCore: FooProtocol
fileprivate init(_ fooCore: FooProtocol) { self.fooCore = fooCore }
// This satisfies the objective-c protocol requirement
final func getBla() -> Bla { return fooCore.getBla() }
}
protocol FooProtocol {
static var possibleValues:[String] { get }
func getBla() -> Bla
}
class FooA : NSObject, FooProtocol {
class var possibleValues:[String] {
return [
"Value A1",
"Value A2",
"Value A3"
]
}
func getBla() -> Bla {
return Bla(withValues: FooA.possibleValues)
}
}
class FooB : NSObject, FooProtocol {
class var possibleValues:[String] {
return [
"Value B1",
"Value B2",
"Value B3",
"Value B4"
]
}
func getBla() -> Bla {
return Bla(withValues: FooB.possibleValues)
}
}

Overriding a generic method with void type T in swift causes the compiler to seg fault

Given:
class MyGenericSuperClass<T> {
func randomMethod(param:T) {
print("SuperClass")
}
}
class MyGenericSubClass : MyGenericSuperClass<Void> {
override func randomMethod(param:Void) {
print("SubClass")
}
}
The following will compile:
class test {
init() {
let test1 = MyGenericSuperClass<Void>()
test1.randomMethod() // outputs 'SubClass'
let test2:MyGenericSuperClass<Void> = MyGenericSubClass()
test2.randomMethod() // outputs 'SubClass'
}
}
But this causes a segmentation fault 11:
class test {
init() {
let test2 = MyGenericSubClass()
test2.randomMethod()
}
}
The only difference is the storing of the subclass in a super class variable.
Is this a compiler bug or is there something else at play here?
Background:
This was coming from a Command<TArg> class with an ActionCommand : Command<Void> subclass and then MySpecificActionCommand subclass
First, you're not properly overriding randomMethod. It should be:
class MyGenericSubClass<T> : MyGenericSuperClass<Void> {
override func randomMethod(param:Void) {
print("SubClass")
}
}
As far as I can tell this should work, so I'm guessing it's a bug. Messing around a bit, it seems to be due to MyGenericSuperClass<Void>. If you change it to something else, e.g. MyGenericSuperClass<String> everything works properly.
You need to define MyGenericSubClass like this to work properly.
class MyGenericSubClass<T> : MyGenericSuperClass<T> {
override func randomMethod(param:T) {
print("SubClass")
}
}

Enum in inheritance

I have multiple classes deriving from one base class with a polymorphic method that accepts the enum type declared in the base class. I repeat the enum in the subclasses so that each subclass only accepts its own specific group of values:
class Character {
enum Actions {
}
func performAction(action: Actions) {
// Functions to be performed by all subclasses
}
}
class Warrior: Character {
enum Actions {
case Attack, Block, Charge
}
override func performAction(action: Actions) {
// Add subclass-specific behavior
}
}
class Wizard: Character {
enum Actions {
case Attack, CastSpell, Run
}
override func performAction(action: Actions) {
// Add subclass-specific behavior
}
}
This of course doesn't work and I get
'Actions' is ambiguous for type lookup in this context.
I can't delete the enum in the base class because then I get an undeclared type error for the method. I have a strong feeling I'm going about this all wrong and trying to reinvent the wheel. Can someone point me in the right direction? Thank you.
How about this approach:
enum Action {
case Attack, Block, Charge, CastSpell, Run
}
class Character {
final func performAction(action: Action) {
if self.allowedActions().contains(action) {
self.executeAction(action);
}
}
func allowedActions() -> [Action] {
// to be overriden in subclasses
return []
}
func executeAction(action: Action) {
// this will also be overriden in subclasses
}
}
class Warrior: Character {
override func allowedActions() -> [Action] {
return [.Attack, .Block, .Charge]
}
override func executeAction(action: Action) {
// do whatever is needed
}
}
class Wizard: Character {
override func allowedActions() -> [Action] {
return [.Attack, .CastSpell, .Run]
}
override func executeAction(action: Action) {
// do whatever is needed
}
}
You use one enum to hold all possible actions, and you define per subclass which actions are allowed.
This way you can treat all characters the same: ask for the actions they can perform, so you can show a menu for example, and then ask the character to perform that action.
We can go even further, by using structs instead of classes and associated values for enums, this being a more swift-ish approach, but also a little bit more complicated to setup (but more logical).

how can I make this Swift event handler boilerplate more concise?

I've seen a pattern in Java that lets you implement a subset of a list of callbacks, in a type-safe way, inline with the class that uses the callbacks:
registerHandlers(new ClassWithNoOpMethods() {
#override
public void onFooEvent(FooEvent event) { ... }
#override
public void onBarEvent(BarEvent event) { ... }
}
All nice and type-safe. I'd like to do the same thing in Swift, but some googling didn't turn up any (IMHO) elegant solutions. So I came up with this:
let registrar = EventSource.getEventRegistrar()
registrar.onFooEvent = { event in doSomethingFoo(event) }
registrar.onBarEvent = { event in doSomethingBar(event) }
...
EventSource.removeEventCallbacks(registrar)
This works fine for consuming the events - its just the subset of events I'm interested in, it lets me define the code inline, etc etc.
However, when I actually implemented this, I got a lot of repeated, boilerplate, non-DRY code. It offends me, but I can't figure out a better way to implement the scheme shown above. I'd like to appeal to the Swift gods on StackOverflow to show me a more concise way to implement this.
Here is what it looks like now:
public class Phone {
...phone stuff...
public class PhoneEventRegistrar {
let phone : Phone
init(phone : Phone) {
self.phone = phone
}
public typealias OnErrorCallback = (PhoneErrorType, String) -> Void
private var onErrorValue : OnErrorCallback?
public var onError : OnErrorCallback {
get { return onErrorValue != nil ? onErrorValue! : {_,_ in} }
set {
assert(onErrorValue == nil, "onError cannot be set twice")
onErrorValue = newValue
}
}
func invokeErrorCallback(type : PhoneErrorType, message : String) {
if let onErrorValue = onErrorValue {
onErrorValue(type, message)
}
}
public typealias OnCallStateChangeCallback = (CallState) -> Void
private var onCallStateChangeValue : OnCallStateChangeCallback?
public var onCallStateChange : OnCallStateChangeCallback {
get { return onCallStateChangeValue != nil ? onCallStateChangeValue! : {_ in} }
set {
assert(onCallStateChangeValue == nil, "onCallStateChange cannot be set twice")
onCallStateChangeValue = newValue
}
}
func invokeCallStateChangeCallback(state : CallState) {
if let onCallStateChangeValue = onCallStateChangeValue {
onCallStateChangeValue(state)
}
}
// and the mostly-similar code shown twice above is repeated for
// each possible callback
}
func invokeErrorCallbacks(type : PhoneErrorType, message : String) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
registrars.forEach({$0.invokeErrorCallback(type, message: message)})
}
func invokeCallStateChangeCallbacks(state : CallState) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
registrars.forEach({$0.invokeCallStateChangeCallback(state)})
}
// again, the mostly similar block of code shown twice above is
// repeated for each possible callback
private var registrars : [PhoneEventRegistrar] = []
public func getPhoneEventRegistrar() -> PhoneEventRegistrar {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
let registrar = PhoneEventRegistrar(phone: self)
registrars.append(registrar)
return registrar
}
public func removeRegistrarCallbacks(registrar : PhoneEventRegistrar) {
objc_sync_enter(self)
defer { objc_sync_exit(self) }
assert(registrars.contains({$0 === registrar}), "cannot remove callbacks, no matching PhoneEventRegistrar found")
registrars = registrars.filter({$0 !== registrar})
}
}
If folks see an alternative implementation that has the same usability benefits for the event consumers, i'd love to see those too. Here are some of the other options I've thought of or tried:
implement a protocol defining the callbacks. Have event consumers implement the protocol and register that for callbacks. Negative: requires all methods to be implemented - forces too many no-op callbacks.
as above, but extend the protocol with default blank implementations. Negative: still requires the event consumer to implement an extra class for the callbacks. Also, lack of dynamic dispatch for protocol extensions means registering the protocol will force generated events to go to the no-op implementation instead of the real event handler.
set the consuming class as a delegate on the event producer. Negative: still have to implement no-op callbacks. I've only ever seen one delegate per event producer, and I need several. #Darko comments below are prompting me to consider this option further.
NSNotificationCenter
There are multiple solutions for your problem. One could be to simply use NSNotificationCenter instead of implementing your own event mechanism.
With NSNotificationCenter you can register for events:
NSNotificationCenter.defaultCenter().addObserver(
self,
selector: #selector(MyClass.myMethod),
name: "com.mycompany.myEvent1",
object: userData)
And send events from anywhere:
let userData: [NSObject: AnyObject] = [anyObject: anyDataToSend]
NSNotificationCenter.defaultCenter.postNotificationName("com.mycompany.myEvent1", object: userData)
You will find plenty of tutorials on SO and Google regarding NSNotificationCenter.
Delegate with optional protocol
Another method would be to use the delegate pattern. Create a protocol and mark it as #objc, in this way protocol methods can be marked as "optional".
#objc protocol MyEventProtocol: class {
optional func foo() -> Bool
func bar()
}
Every object which conforms to this protocol now must implement bar() but can implement optionally foo().
class MyEventReceiver: MyEventProtocol {
func bar() { // do something }
}
Then your event sender class can do something like this:
class MyEventSender {
weak var delegate: MyEventProtocol? // the name "delegate" is just convention, you can use any other name
init(receiver: MyEventReceiver) {
self.delegate = receiver
}
func sendEventToReceiver() {
if let delegate = self.delegate {
delegate.func() // guaranteed by the protocol
delegate.foo?() // foo is marked as optional, so you have to check it with ?. If foo is implemented on the receiver it will be called, otherwise not.
}
}
}
That's the basic principle. In this way you can define one protocol for all possible events but the implementer of the protocol only have to implement the methods which are not marked as optional. They are "required".
Protocol extensions with default methods
A third method would be to create a protocol extension with default methods.
protocol MyEventProtocol: {
func bar()
}
extension MyEventProtocol {
func foo() -> Bool {
return true
}
}
Then the implementor of MyEventProtocol does not have to implement foo() because there is already an implementation. (it's a kind of a "faked" #objc protocol with optional methods) If you add some generic mechanism to this solution you could also prevent the hefty code duplication. (generics in Protocols are done with associatedtype in Swift 2.2, see other tutorials)