I have define 2 protocols.
I need the first one (NameProtocol) to enforce the Equatable protocol.
While the other class (BuilderProtocol) have a method that return the first one (NameProtocol).
public protocol NameProtocol : Equatable {
var name: String { get }
}
public protocol BuilderProtocol {
func build() -> NameProtocol? // Compiler error
init()
}
The compiler error :
"Protocol 'NameProtocol' can only be used as a generic constraint because it has Self or associated type requirements"
I need the object return by build() to return an object conforming to the NameProtocol and on which I can define ==
Is there a way I can make this work?
Thanks
If using a typealias in BuilderProtocol how can I make the array declaration work?
public protocol OtherRelatedProtocol {
var allNames : Array<NameProtocol> { get }
}
Conclusion
I will remove the Equatable and implement an isEqual method.
public protocol NameProtocol {
func isEqual(nameable: NameProtocol) -> Bool
var name: String { get }
}
If you're familiar with Java or C#, Swift protocols are about halfway between generics and interfaces. One thing that you can do in a protocol, for instance, is this:
protocol Foo {
func compareWith(foo: Self)
}
Classes that implement this protocol will have a method compareWith that accept an object of their own type (and not an object of type Foo).
This is what the compiler calls "Self or associated type requirements", and this is how Equatable is defined (it needs an operator== that accepts two Self operands). The downside of these protocols, though, is that you can only use them as generic constrains: you can't use them as an expression type.
The solution is to use generics. In this case, you'd make your ProtocolBuilder protocol generic, with a constraint that the type implements NameProtocol.
public protocol NameProtocol : Equatable {
var name: String { get }
}
public protocol BuilderProtocol {
typealias T: NameProtocol
func build() -> T?
init()
}
Related
I'd like to have a generic weak reference to an object and parametrize it by a protocol that is class-bound.
Here is the code example that does not work in my case:
protocol Protocol: class { // also written as `protocol Protocol: AnyObject {`
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: AnyObject {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak<Protocol>(property: a) // error: 'Weak' requires that 'Protocol' be a class type
I get an error on last line: 'Weak' requires that 'Protocol' be a class type.
As Protocol will always be of class type (which is the same as AnyObject) shouldn't that be allowed by the compiler?
Is it possible to resolve that issue with swift 4?
If not, is it a limitation that can be resolved in a future version of swift or is it something impossible that the type system can not allow to happen?
A not accepted solution is to use #objc to the protocol declaration as in:
#obc protocol Protocol: class {
func function()
}
as this leads to limitations.
You are saying:
final class Weak<Type> where Type: AnyObject {
So you yourself are requiring that Type be a class (because that is exactly what AnyObject means).
A protocol is not a class. It is a protocol.
This is currently impossible because protocols do not conform to themselves. A protocol is not a type; it is a recipe for a type. As the simplest example of why this is hard, consider this situation:
protocol X {
init()
}
func f<T: X>(type: T.Type) -> T {
return type.init()
}
f(type: X.self)
This would create a value of type X, but would that be? This isn't allowed, and the mechanism that prevents it is that protocols do not conform to themselves. This crops up in a lots of other ways, and your example is one of them.
Some of this will be addressed when more of the Generics Manifesto is implemented, particularly the section Generalized Existentials, but currently what you want isn't possible. You can't have a "weak reference to some unknown thing." You need to know what that thing is.
The standard solution to this problem is a box, not a protocol. See Weak Arrays for an example.
If I understand your problem I design this solution
First I created a protocol called WeakProtocol, this will be our base of protocols
protocol WeakProtocol : AnyObject {}
After change your protocol to extends this new WeakProtocol
protocol Protocol: WeakProtocol {
func function()
}
after your Weak class you need apply a WeakProtocol type example
final class Weak<Type> where Type: WeakProtocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
Now to implement you don't need say it Protocol because the constructor receive the protocol.
Complete code is
protocol WeakProtocol : AnyObject {}
protocol Protocol: WeakProtocol {
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: WeakProtocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak(property: a)
You can too only change Protocol to extends AnyObject and Weak class to Type:Protocol, like this
protocol Protocol: AnyObject {
func function()
}
final class A: Protocol {
func function() {}
}
final class Weak<Type> where Type: Protocol {
final private weak var property: Type?
init(property: Type) {
self.property = property
}
}
let a = A()
let something = Weak(property: a)
I want to create a Wrapper class for a generic class that is conforming a generic protocol, but for some reason I cannot make it work properly.
The idea behind is to use the wrapper AnyNetworkRequest as an Erased-Type along the application, so that there is no need to define the Generic types as in _NetworkRequest.
I cannot see what is missing/wrong on AnyNetworkRequest. If any could point me out what is missing or wrong I'd appreciate it.
// Protocol with associatedtypes
public protocol NetworkRequest {
associatedtype RequestSerializationType: RequestSerializationProtocol
associatedtype RequestResponseType: NetworkResponseProtocol
var requestSerializer: RequestSerializationType { get }
var requestResponse: RequestResponseType? { get }
}
// Generic Request
public class _NetworkRequest<RequestSerializationType: RequestSerializationProtocol, RequestResponseType: NetworkResponseProtocol>: NetworkRequest {
fileprivate init() {}
public lazy var requestSerializer: RequestSerializationType = { RequestSerializationType.init() }()
public var requestResponse: RequestResponseType?
}
// Concrete Request
public class DataNetworkRequest: _NetworkRequest<ConcreteHTTPRequestSerializer, ConcreteDataNetworkResponse> {}
// Concrete Request
public class JSONDataNetworkRequest: _NetworkRequest<ConcreteJSONRequestSerializer, ConcreteJSONDataNetworkResponse> {}
// Type Erased Wrapper
// Cannot make this wrapper work
// Error 1: Type 'AnyNetworkRequest' does not conform to protocol 'NetworkRequest'
// Error 2: Reference to invalid associated type 'RequestSerializationType' of type 'AnyNetworkRequest'
public class AnyNetworkRequest : NetworkRequest { //E1
private let request : _NetworkRequest<RequestSerializationType, RequestResponseType> //E2
init<T: NetworkRequest>(_ networkRequest: T) where T.RequestSerializationType == RequestSerializationType, T.RequestResponseType == RequestResponseType {
request = networkRequest
}
}
EDITED: 1st MODIFICATION
// Protocol with associatedtypes
public protocol NetworkRequest {
associatedtype RequestSerializationType: RequestSerializationProtocol
associatedtype RequestResponseType: NetworkResponseProtocol
var requestSerializer: RequestSerializationType { get }
var requestResponse: RequestResponseType? { get }
}
// Generic Request
public class _NetworkRequest<RST: RequestSerializationProtocol, RRT: NetworkResponseProtocol>: NetworkRequest {
public typealias RequestSerializationType = RST
public typealias RequestResponseType = RRT
fileprivate init() {}
public lazy var requestSerializer: RequestSerializationType = { RequestSerializationType.init() }()
public var requestResponse: RequestResponseType?
}
// Concrete Request
public class DataNetworkRequest: _NetworkRequest<ConcreteHTTPRequestSerializer, ConcreteDataNetworkResponse> {}
// Concrete Request
public class JSONDataNetworkRequest: _NetworkRequest<ConcreteJSONRequestSerializer, ConcreteJSONDataNetworkResponse> {}
// Type Erased Wrapper
// Cannot make this wrapper work
// Error 1: Type 'AnyNetworkRequest' does not conform to protocol 'NetworkRequest'
// Error 2: Reference to invalid associated type 'RequestSerializationType' of type 'AnyNetworkRequest'
public class AnyNetworkRequest : NetworkRequest { //E1
/* // E1 forces me to include typealiases
public typealias RequestSerializationType = <#type#>
public typealias RequestResponseType = <#type#>
*/
private let request : _NetworkRequest<RequestSerializationType, RequestResponseType>
var requestSerializer: RequestSerializationType { //E2
return request.requestSerializer
}
var requestResponse: RequestResponseType? {
return request.requestResponse
}
init<T: NetworkRequest>(_ networkRequest: T) where T.RST == RequestSerializationType, T.RRT == RequestResponseType {
request = networkRequest
}
}
Errors are quite straightforward to explain.
1) Your AnyNetworkRequest class really does not conform to NetworkRequest protocol. And I don't see why it should, by the way. Unsatisfied requirements are requestSerializer and requestResponse properties along with needed type aliases. In general, you may rewrite this as following:
public class AnyNetworkRequest: NetworkRequest {
var requestSerializer: RequestSerializationType {
return request.requestSerializer
}
var requestResponse: RequestResponseType? {
return request.requestResponse
}
private let request : _NetworkRequest<RequestSerializationType, RequestResponseType>
// ...
}
BUT it takes us to
2) Where you need to specify something for associated types. You cannot use RequestSerializationType and RequestResponseType in generic declaration as they are not concrete types.
So you cannot perform type erasure in such manner.
I don't know why you need to get rid of generics here aside of typing less letters, but what I can offer is to use type aliases like:
typealias DataNetworkRequest = _NetworkRequest<ConcreteHTTPRequestSerializer, ConcreteDataNetworkResponse>
typealias JSONDataNetworkRequest = _NetworkRequest<ConcreteJSONRequestSerializer, ConcreteJSONDataNetworkResponse>
This way you will elude redundant inheritance and have more clearly expressed types in case it's your goal.
AnyNetworkRequest will not be needed at all in this case.
This is not actually how type erasers work - the role of type erasers is to allow homogenous interfaces in a heterogenous world, where many types can conform to the protocols interested into.
Take for example AnySequence, it's interface is similarly to this:
struct AnySequence<Element>: Sequence {
init<S>(_ sequence: S) where S == Sequence, S.Element == Element
}
AnySequence erases the original sequence type, not the Element type. In your case you cannot get rid of the two associated types, a type eraser can only hide the actual class that conforms to NetworkRequest. AnyRequest would still need information about the two types.
I have been struggling to find a solution using generics and associated types inside another associated type for the problem above
Case
I want to have an ObjectRequestType, which inside it has an associated type of type ObjectResponseType.
protocol ObjectRequestType {
associatedtype Response: ObjectResponseType
}
ObjectResponseType on the other hand is a protocol having associated type Element
protocol ObjectResponseType {
associatedtype Element
}
What I want to achieve is that I want to extend the functionality of ObjectRequestType depending on different type of elements, that here for the sake of example we have two different types of Element.
protocol ElementType {}
protocol OtherElementType {}
So far I would implement this by the following extensions
extension ObjectRequestType where Response.Element: ElementType {
static func request() {
print("ElementType")
}
}
extension ObjectRequestType where Response.Element: OtherElementType {
static func request() {
print("OtherElementType")
}
}
The extra step would be to handle to pass this request to a class which I need using generics
class DemoClass<Request: ObjectRequestType> {
static func execute() {
Request.request()
}
}
Problem
Since on the fly DemoClass cannot define what kind of Response the Request has it will find two implementations of it, and it will fail throwing the compilation error
error: ambiguous reference to member 'request()'
Modifying the class by adding an extra where clause still won't do it, because I will miss the rest of the implementation of OtherElementType
class DemoClass<Request: ObjectRequestType> where Request.Response.Element: ElementType {
static func execute() {
Request.request()
}
}
I have been trying workarounds about it, but still I haven't been able to implement this kind of case. If anybody has any idea or another approach, it would be happily welcomed.
The usual way to do this is to add the request method to the ObjectResponseType protocol so you can guarantee that it exists on any conforming type. Then you create a protocol extension providing the default implementation for the types you know how to handle, which you've already done. If you need to override the request for a certain request with one of the existing element types, you can do that. If you need to support another element type, you can either do it right in the request or add another protocol extension.
protocol ObjectResponseType {
associatedtype Element
}
protocol ObjectRequestType {
associatedtype Response: ObjectResponseType
static func request()
}
protocol ElementType {}
extension ObjectRequestType where Response.Element: ElementType {
static func request() {
print("ElementType")
}
}
protocol OtherElementType {}
extension ObjectRequestType where Response.Element: OtherElementType {
static func request() {
print("OtherElementType")
}
}
class DemoClass<Request: ObjectRequestType> {
static func execute() {
Request.request()
}
}
class Foo: ElementType {}
class FooResponse: ObjectResponseType {
typealias Element = Foo
}
class FooRequest: ObjectRequestType {
typealias Response = FooResponse
}
class Bar: OtherElementType {}
class BarResponse: ObjectResponseType {
typealias Element = Bar
}
class BarRequest: ObjectRequestType {
typealias Response = BarResponse
// Override the default implementation
static func request() {
print("Bar")
}
}
class Baz {}
class BazResponse: ObjectResponseType {
typealias Element = Baz
}
class BazRequest: ObjectRequestType {
typealias Response = BazResponse
static func request() {
print("Baz")
}
}
DemoClass<FooRequest>.execute() // ElementType
DemoClass<BarRequest>.execute() // Bar
DemoClass<BazRequest>.execute() // Baz
The Swift protocol definition is empty:
public protocol CVarArgType {
}
The Apple documentation page doesn't list any required methods:
https://developer.apple.com/library/ios/documentation/Swift/Reference/Swift_CVarArgType_Protocol/index.html
So I would expect this to work:
extension String : CVarArgType {
}
but I get a build error: Protocol requires property '_cVarArgEncoding' with type '[Int]' (Swift.CVarArgType)
Where does this requirement come from, given that the protocol definition is empty?
Moving forward if I implement the computed property:
extension String : CVarArgType {
public var _cVarArgEncoding: [Int] {
get {
//What is expected to be returned here?
}
}
}
What is expected to be returned as an array of Int?
Updated: Why do I need this?
I have a protocol named Identifiable that my Core Data entity model classes conform to, I have an extension to this protocol with a couple of constraints to provide a function that uses the id value in an NSPredicate with format constructor which requires the CVarArgType.
public protocol Identifiable {
typealias IdentityType: CVarArgType, Hashable
var id: IdentityType { get }
}
extension Identifiable where Self: Findable, Self: NSManagedObject {
static public func find(id: IdentityType, context: NSManagedObjectContext) -> Self? {
return find(NSPredicate(format: "id = %#", id), context: context)
}
}
public extension Findable where Self: NSManagedObject {
static public func find(predicate: NSPredicate?, context: NSManagedObjectContext) throws -> Self? {
let fetchRequest = fetchRequestForEntity(inContext: context)
fetchRequest.predicate = predicate
fetchRequest.fetchLimit = 1
return try context.executeFetchRequest(fetchRequest).first as? Self
}
}
I don't think that you should be trying to conform other types to them. The Swift source code says:
Note: the protocol is public, but its requirement is stdlib-private.
That's because there are APIs operating on CVarArg instances, but defining conformances to CVarArg outside of the standard library is not supported.
The stdlib is special in quite a few ways and hooks deeper into the build system than user code can. One example of this is that many stdlib functions can be inlined into your own code which is not currently possible across module boundaries in other cases.
error: protocol 'Protocol' requirement 'instance' cannot be satisfied by a non-final class ('Class') because it uses 'Self' in a non-parameter, non-result type position
protocol Protocol {
var instance: Self {get}
}
class Class: Protocol {
var instance: Class {return Subclass()}
}
class Subclass: Class {}
Here is how I would express what I want, in C#. (C# does not, to my knowledge, have a way to enforce that the generic parameter "Self" is actually the Self we know from Swift, but it functions well enough as documentation that should make me do the right thing.)
interface Protocol<Self> where Self: Protocol<Self> {
Self instance {get;}
}
class Class: Protocol<Class> {
public Class instance {get {return new Subclass();}}
}
class Subclass: Class {}
…how that might look in a future version of Swift:
protocol Protocol {
typealias FinalSelf: Protocol where FinalSelf.FinalSelf == FinalSelf
var instance: FinalSelf {get}
}
class Class: Protocol {
var instance: Class {return Subclass()}
}
class Subclass: Class {}
How I'm emulating the portion of that which is relevant to my problem:
protocol Protocol: ProtocolInstance {
static var instance: ProtocolInstance {get}
}
protocol ProtocolInstance {}
class Class: Protocol {
static var instance: ProtocolInstance {return Subclass()}
}
class Subclass: Class {}
And, here is what I believe to be the relevant portion of my code:
protocol Protocol {
static var 🎁: Self? {get} // an existing instance?
static var 🐥: Self {get} // a new instance
func instanceFunc()
}
extension Protocol {
static func staticFunc() {
(🎁 ?? 🐥).instanceFunc()
}
}
As it says, you can't do this, and for good reason. You can't prove you'll keep your promise. Consider this:
class AnotherSubclass: Class {}
let x = AnotherSubclass().instance
So x should be AnotherSubclass according to your protocol (that's Self). But it'll actually be Subclass, which is a completely different type. You can't resolve this paradox unless the class is final. This isn't a Swift limitation. This limitation would exist in any correct type system because it allows an type contradiction.
On the other hand, something you can do is promise that instance returns some consistent type across all subclasses (i.e. the superclass). You do that with an associated type:
protocol Protocol {
typealias InstanceType
var instance: InstanceType {get}
}
class Class: Protocol {
var instance: Class {return Subclass()}
}
class Subclass: Class {}
class AnotherSubclass: Class {}
let x = AnotherSubclass().instance
Now x is unambiguously of type Class. (It also happens to be random other subclass, which is kind of weird, but that's what the code says.)
BTW, all of this usually suggests that you're using subclassing when you really shouldn't be. Composition and protocols would probably solve this problem better in Swift. Ask yourself if there's any reason that Subclass needs to actually be a subclass of Class. Could it be an independent type that conforms to the same protocol? All kinds of problems go away when you get rid of subclasses and focus on protocols.
I've been thinking about this more, and there may be a way to get what you're looking for. Rather than saying that all subclasses implement instance, attach instance as an extension. You can still override that if you want to return something else.
protocol Protocol {
init()
}
class Class: Protocol {
required init() {}
var instance: Class { return Subclass() }
}
extension Protocol {
var instance: Self { return self.dynamicType.init() }
}
class Subclass: Class {}
This dodges the inheritance problem (you can't create the same "AnotherClass returning the wrong type" this way).
This would actually make sense and work if you don't want to actually return Self for every subclass like this:
protocol Protocol : class {
typealias Sub : Self
var instance: Sub {get}
}
Which means that your protocol defines a typealias that has to be a subclass of itself. The following code would just work:
class Class: Protocol {
var instance: Class {return Subclass()}
}
class Subclass: Class {}
Class().instance // Returns SubClass()
However the code above doesn't compile with the error
error: inheritance from non-protocol, non-class type '`Self`'
which I think is a bug, because Self is declared as a class type. You can however make it somehow work like this:
protocol Protocol : class {
typealias Sub : Class
var instance: Sub {get}
}
but then you don't have much of the protocol itself because only the class itself should ever conform to it.