Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Cannot declare a public protocol extension with internal requirements

I am programming a media player app and created my own framework for managing all the player functionality. In this framework I have a public protocol called PlayerControllerType and an internal protocol _PlayerControllerType. In PlayerControllerType I have declared all the methods and properties, which should be accessible from outside the framework. In _PlayerControllerType I have defined a couple of properties, which are used by the concrete types implementing PlayerControllerType inside the framework. One of these types is PlayerController. Its declaration is as follows:

public class PlayerController<Item: Equatable>: NSObject, PlayerControllerType, 
_PlayerControllerType, QueueDelegate

Now I want to provide a couple of default implementations for the classes in my framework, which conform to PlayerControllerType and the internal _PlayerControllerType, for example:

import Foundation  
import MediaPlayer  

public extension PlayerControllerType where Self: _PlayerControllerType, Item == MPMediaItem, Self.QueueT == Queue<Item>, Self: QueueDelegate {  

    public func setQueue(query query: MPMediaQuery) {  
        queue.items = query.items ?? []  
    }  

}  

This works as expected in Xcode 7 Beta 4. Yesterday I updated to Beta 6 and got this error: "Extensions cannot be declared public because its generic requirement uses an internal type" (also see screenshot). The error in Xcode

I find this error irritating. Of course no type outside of my framework benefits of this extension because it cannot access the internal protocol _PlayerControllerType, but it is very useful for the types inside my framework which implement both PlayerControllerType and _PlayerControllerType.

Is this just a bug in the Swift compiler or is this the intended behavior? It's is pretty unfortunate that this doesn't work anymore because now I have to put these methods into a newly created base class for all my PlayerControllers.

Any help or feedback would greatly appreciated.

Kai

EDIT: Here is a shortened example of the protocols and their extensions:

public protocol PlayerControllerType {
    typealias Item
    var nowPlayingItem: Item {get}
    func play()
}

protocol _PlayerControllerType {
    var nowPlayingItem: Item {get set}
}

public extension PlayerControllerType where Self: _PlayerControllerType {

    /* 
    I want to provide a default implementation of play() for
    all my PlayerControllers in my framework (there is more than one).
    This method needs to be declared public, because it implements a
    requirement of the public protocol PlayerControllerType. 
    But it cannot be implemented here, because this extension 
    has the requirement _PlayerControllerType. It needs this requirement,
    because otherwise it cannot set the nowPlayingItem. I don't want to
    expose the setter of nowPlayingItem.
    I could make a base class for all PlayerControllers, but then I'm
    restricted to this base class because Swift does not support
    multiple inheritance.
    */
    public func play() {
        if nowPlayingItem == nil {
            nowPlayingItem = queue.first
        }
        // Other stuff
    }

}
like image 223
Kai Engelhardt Avatar asked Sep 07 '15 19:09

Kai Engelhardt


1 Answers

You need to declare an access level of the _PlayerControllerType protocol as 'public'.

public protocol _PlayerControllerType {
   // some code
}

According to (The Swift Programming Language - Access Control),

A public members cannot be defined as having an internal or private type, because the type might not be available everywhere that the public variable is used. Classes are declared as internal by default, so you have to add the public keyword to make them public.

A member (class/protocol/function/variable) cannot have a higher access level than its parameter types and return type, because the function could be used in situations where its constituent types are not available to the surrounding code.

like image 93
Krunal Avatar answered Sep 30 '22 11:09

Krunal