5

I'm used to having default parameters inside protocols using extensions, as protocol declarations themselves can't have them, like this:

protocol Controller {
   func fetch(forPredicate predicate: NSPredicate?)
}

extension Controller {
   func fetch(forPredicate predicate: NSPredicate? = nil) {
      return fetch(forPredicate: nil)
   }
}

Worked perfectly for me.

Now I have the next situation, I have one specific protocol for specific kind of controller:

protocol SomeSpecificDatabaseControllerProtocol {
    //...
    func count(forPredicate predicate: NSPredicate?) -> Int
}

And protocol-extension with implementations of default methods for controllers:

protocol DatabaseControllerProtocol {
    associatedtype Entity: NSManagedObject
    func defaultFetchRequest() -> NSFetchRequest<Entity>
    var context: NSManagedObjectContext { get }
}

extension DatabaseControllerProtocol {
    func save() {
        ...
    }

    func get() -> [Entity] {
        ...
    }

    func count(forPredicate predicate: NSPredicate?) -> Int {
        ...
    }

    //.....
}

My issue is when I'm trying to add method with default parameter to the SomeSpecificDatabaseControllerProtocol extension, I'm receiving a compile-time error, that concrete class conforming to SomeSpecificDatabaseControllerProtocol doesn't conform to the protocol (happens only if I extend protocol):

class SomeClassDatabaseController: SomeSpecificDatabaseControllerProtocol, DatabaseControllerProtocol {...}

What am I missing?

Vladyslav Zavalykhatko
  • 15,202
  • 8
  • 65
  • 100

1 Answers1

2

This is happening because compiler is confuse due to ambiguous functions.

  1. Here SomeClassDatabaseController receiving count() method from two different protocols.

  2. DatabaseControllerProtocol has count(forPredicate) method which always need parameter.

  3. On other hand SomeSpecificDatabaseControllerProtocol have count() method which can have empty parameter.

  4. To solve this either you have to change count method in DatabaseControllerProtocol to this or you have to implement it in SomeClassDatabaseController.

func count(forPredicate predicate: NSPredicate? = nil) -> Int { return 0}

Community
  • 1
  • 1
Martin
  • 846
  • 1
  • 9
  • 23
  • yes, exactly, that was what I've just understood :) the most painless way is to change the interface of func with `DatabaseControllerProtocol` declaration – Vladyslav Zavalykhatko Jan 12 '18 at 09:43
  • Sometimes we need to be more specific. We cannot always rely on tools. Or there has to be away to specify which class method it should call. – Martin Jan 12 '18 at 09:51