dependency injection and protocols

I had a posting in the older forums about this issue. I never really found a solution. Maybe I can try posting again and see if anyone has some good advice.


I am a big fan of TDD. One of the techniques I picked up was dependency-injection. Objective-C is a very laid-back language when it comes to type-checking. It is very easy for the compiler to let you swap a test-double class for a production class. I am having a problem in Swift that you might be able to help with.


class ChildClass { }

class ParentClass {
   func child() -> ChildClass {
       return ChildClass()
   }
}

protocol ChildProtocol { }

extension ChildClass: ChildProtocol { }

protocol ParentProtocol {
   func child() -> ChildProtocol
}

extension ParentClass: ParentProtocol { }


This code is failing to build. Swift does not believe that ParentClass can conform to ParentProtocol. This is a contrived example. I will show you a real example where I would use this pattern in a real app.


import Foundation

protocol SessionTaskType { }

extension NSURLSessionDataTask: SessionTaskType { }

protocol SessionType {
   func dataTaskWithRequest(request: NSURLRequest, completionHandler: (NSData?, NSURLResponse?, NSError?) -> Void) -> SessionTaskType?
}

extension NSURLSession: SessionType { }


Here is another example that fails.


protocol QueueType {
    static func mainQueue() -> QueueType
}
extension NSOperationQueue: QueueType { }


I filed a radar last year. Can anyone please explain if this is a real bug in the compiler or if this is just the intended behavior. Does anyone have a workaround that would make these examples compile correctly?

Looks indeed like a bug where the compiler doesn't understand the return type covariance from ChildClass to ChildProtocol for the method child().


Changing line 3 from

func child() -> ChildClass {

to

func child() -> ChildProtocol {

works.

rdar://17906373

I don't think that's a bug. But if it is, wouldn't this be a much simpler way to demonstrate the (same) bug:

protocol Fooable {
    func foo() -> BooleanType
}

struct SomeType: Fooable { // Error: Type 'SomeType' does not conform to protocol 'Fooable'
    func foo() -> Bool { return true }
}

?

(Yes, changing both to BooleanType or Bool will make it compile.)


If the above did compile, wouldn't there be all sorts of crazy implications?


Or, are you saying this should work for reference types but not for value types?

By definition, Bool conforms to BooleanType. What exactly are the crazy implications you would see from compiling this code?

I can't come up with any good examples, but here is a related thread.

dependency injection and protocols
 
 
Q