Protocol Oriented Programming and the Delegate Pattern

A WWDC 2015 session video describes the idea of Protocol-Oriented Programming, and I want to adopt this technique in my future apps. I've been playing around with Swift 2.0 for the last couple of days in order to understand this new approach, and am stuck at trying to make it work with the Delegate Pattern.

I have two protocols that define the basic structure of the interesting part of my project (the example code is nonsense but describes the problem):


1) A delegation protocol that makes accessible some information, similar to UITableViewController's dataSource protocol:

protocol ValueProvider {
   var value: Int { get }
}


2) An interface protocol of the entity that does something with the information from above (here's where the idea of a "Protocol-First" approach comes into play):

protocol DataProcessor {
   var provider: ValueProvider { get }
   func process() -> Int
}


Regarding the actual implementation of the data processor, I can now choose between enums, structs, and classes. There are several different abstraction levels of how I want to process the information, therefore classes appear to fit best (however I don't want to make this an ultimate decision, as it might change in future use cases). I can define a base processor class, on top of which I can build several case-specific processors (not possible with structs and enums):

class BaseDataProcessor: DataProcessor {
   let provider: ValueProvider

   init(provider: ValueProvider) {
       self.provider = provider
   }

   func process() -> Int {
       return provider.value + 100
   }
}

class SpecificDataProcessor: BaseDataProcessor {
   override func process() -> Int {
       return super.process() + 200
   }
}


Up to here everything works like a charm. However, in reality the specific data processors are tightly bound to the values that are processed (as opposed to the base processor, for which this is not true), such that I want to integrate the ValueProvider directly into the subclass (for comparison: often, UITableViewControllers are their own dataSource and delegate).


First I thought of adding a protocol extension with a default implementation:

extension DataProcessor where Self: ValueProvider {
   var provider: ValueProvider { return self }
}


This would probably work if I did not have the BaseDataProcessor class that I don't want to make value-bound. However, subclasses that inherit from BaseDataProcessor and adopt ValueProvider seem to override that implementation internally, so this is not an option.


I continued experimenting and ended up with this:

class BaseDataProcessor: DataProcessor {
   private var _provider: ValueProvider!
   var provider: ValueProvider { return _provider }

   func process() -> Int {
       return provider.value + 10
   }
}

class SpecificDataProcessor: BaseDataProcessor, ValueProvider {
   let value = 1234
   override var provider: ValueProvider { return self }

   override func process() -> Int {
       return super.process() + 100
   }
}


Which compiles and at first glance appears to do what I want. However, this is not a solution as it produces a reference cycle, which can be seen in a Swift playground:

weak var p: SpecificDataProcessor!
autoreleasepool {
   p = SpecificDataProcessor()
   p.process()
}
p // <-- not nil, hence reference cycle!


Another option might be to add class constraints to the protocol definitions. However, this would break the POP approach as I understand it.


Concluding, I think my question boils down to the following: How do you make Protocol Oriented Programming and the Delegate Pattern work together without restricting yourself to class constraints during protocol design?

Accepted Reply

What interests me is this part:

weak var p: SpecificDataProcessor!
autoreleasepool {
   p = SpecificDataProcessor()
   p.process()
}
p // <-- not nil, hence reference cycle!

I don't see why you think this code can detect reference cycle, so just see the following result.

class BaseSimpleClass {}
class SimpleClass: BaseSimpleClass {
    func process() -> Int {
        return 0
    }
}
weak var p: SimpleClass!
autoreleasepool {
    p = SimpleClass()
    p.process()
}
p // <-- not nil, but SimpleClass does produce reference cycle?

It seems using weak var & autoreleasepool in the Playground is not a good tool to detect reference cycle.

(Generally, pure Swift classes do not generate autoreleasing code.)


Add another class which has a clear reference cycle, and run the following code as a CommandLine app:

class ReferenceCycleClass {
    var other: ReferenceCycleClass!
    init() {other = self}

    deinit {
        print("ReferenceCycleClass:deinit")
    }
}

//Added similar deinit to other classes.

var s: SimpleClass? = SimpleClass()
s = nil
var r: ReferenceCycleClass? = ReferenceCycleClass()
r = nil
var p: SpecificDataProcessor? = SpecificDataProcessor()
p = nil

The code above generates the following output:

SimpleClass:deinit
SpecificDataProcessor:deinit

Replies

Is your provider property a strong reference or a weak reference? Delegates and datasources are almost always weak references…

What interests me is this part:

weak var p: SpecificDataProcessor!
autoreleasepool {
   p = SpecificDataProcessor()
   p.process()
}
p // <-- not nil, hence reference cycle!

I don't see why you think this code can detect reference cycle, so just see the following result.

class BaseSimpleClass {}
class SimpleClass: BaseSimpleClass {
    func process() -> Int {
        return 0
    }
}
weak var p: SimpleClass!
autoreleasepool {
    p = SimpleClass()
    p.process()
}
p // <-- not nil, but SimpleClass does produce reference cycle?

It seems using weak var & autoreleasepool in the Playground is not a good tool to detect reference cycle.

(Generally, pure Swift classes do not generate autoreleasing code.)


Add another class which has a clear reference cycle, and run the following code as a CommandLine app:

class ReferenceCycleClass {
    var other: ReferenceCycleClass!
    init() {other = self}

    deinit {
        print("ReferenceCycleClass:deinit")
    }
}

//Added similar deinit to other classes.

var s: SimpleClass? = SimpleClass()
s = nil
var r: ReferenceCycleClass? = ReferenceCycleClass()
r = nil
var p: SpecificDataProcessor? = SpecificDataProcessor()
p = nil

The code above generates the following output:

SimpleClass:deinit
SpecificDataProcessor:deinit

Thanks bob113,


I agree with you that in most cases, using a weak reference to the delegate object is the correct way. Now with the protocols mentioned in my first post, I can't (and don't want to) tell if the delegate is of value type or reference type, and you cannot have weak or unowned references to value types.


Regarding the SpecificDataProcessor I know that the valueProvider is a class and hence reference type, which would suggest a solution with a weak self pointer. I considered this, but found that it is easier to implement a "computed" self-reference which I expected not to generate reference cycles by design:

override var provider: ValueProvider { return self }


I was surprised to see that my Playground/autoreleasepool experiments indeed indicated a reference cycle. Now OOPer says that I have no actual proof of a reference cycle, and I'll investigate this further.

Thank you OOPer!


Wow, that's interesting. You are right, when run as a command line app, there's indeed no reference cycle. That's also reassuring because I wouldn't know where I introduced the cycle. I'll mark your answer as correct, thanks!


Now one last question. BaseDataProcessor has the valueProvider property which needs to be set when the class is initialized, whereas SpecificDataProcessor should never accept an external valueProvider during initialization. I came up with a somewhat hacky solution and wonder if there is a cleaner way to achieve this:

class BaseDataProcessor: DataProcessor {
    private var provider_: ValueProvider! // Not great but necessary for the 'var' construct
    var provider: ValueProvider { return provider_ }
   
    init(provider: ValueProvider!) {
        provider_ = provider
    }
   
    func process() -> Int {
        return provider.value + 10
    }
}

class SpecificDataProcessor: BaseDataProcessor, ValueProvider {
    override var provider: ValueProvider { return self } // provider_ is not needed any longer
   
    // Hide the init method that takes a ValueProvider
    private init(_: ValueProvider!) {
        super.init(provider: nil)
    }
   
    // Provide a clean init method
    init() {
        super.init(provider: nil)
       // I cannot set provider_ = self, because provider_ is strong. Can't make it weak either
        // because in BaseDataProcessor it's not clear whether it is of reference or value type
    }
   
    let value = 1234
}

As bob133 suggested and you have already commented, making provider property a weak reference seems to be a natural solution.

protocol ValueProvider: class {
    var value: Int { get }
}
protocol DataProcessor {
    weak var provider: ValueProvider! { get }
    func process() -> Int
}

And that's true we sometimes don't want to tell if the delegate is of value type or reference type .

If Swift had `possibly weak` modifier (weak for reference types, ignored for value types), we could have solved this issue in a cleaner manner.

I, too, think that a "possibly weak" modifier would be a great addition to the Swift language as it would allow for less and cleaner code in such situations. By the way, do you know how to propose this to Apple?

However, I respectfully disagree with your suggestion to make the ValueProvider a "possibly weak" property of the DataProcessor protocol, as this is more of an implementation detail that the protocol shouldn't be aware of. Even worse, this would impose implementation restrictions on entities that adopt this protocol. My understanding of clean protocol-oriented programming is that in the given case the protocol should really only define that there is a get-accessible ValueProvider, which is neither optional nor implicitly unwrapped – everything else is to be handled by the actual implementation (please correct me if I'm wrong!). Still there is a place where the "possibly weak" approach would make sense:

class BaseDataProcessor: DataProcessor {
  private weak-if-reference var _provider: ValueProvider!
  var provider: ValueProvider { return _provider }
  ...
}


But even then, I'm not sure if a weak reference is the better solution per se. I understand that this way I probably wouldn't need a computed property at all (and that might be reason enough), but is there any actual downside of "var provider: ValueProvider { return self }" that I'm not aware of?

I believe I understand what and why you disagree. My proposal may be a short-cut workaround until Swift protocols can become what we expect and need.


I'm not ready to decide which is better, but hope your addressing this issue would help Swift team improve the language.

You can send a feature request using Apple Bug Reporter, you can find Report Bugs link at the bottom of evrery developer page.

I'll definitely do that. Thanks a lot for your efforts!