Swift: Generic Protocols - swift

I have some swift structs for which protocol compliance is generated with individual extensions with equal methods names which just differ in their return types which are struct dependent. On top of That I want to use them in a generic function which Calls a protocol conforming function for a generic type).
I tried to accomplish this like that:
//: Playground - noun: a place where people can play
import UIKit
protocol FooProt {
typealias T;
static func createMe<T>()->T;
}
struct FooStruct{
}
extension FooStruct: FooProt{
typealias T = FooStruct;
static func createMe () -> FooStruct{
return FooStruct();
}
}
class Creator{
fun createOne<T where T:FooProt>(type:T.Type){
let instance = T.createMe();
}
}
Unfortunately I get the following error :
/var/folders/sn/78_zvfd15d74dzn01mdv258h0000gq/T/./lldb/3741/playground6.swift:7 :17: note: protocol requires function 'createMe()' with type ' () -> T' (aka '<τ_1_0> () -> τ_1_0')
static func createMe()->T;
What exactly doesn't comply here and is there a workaround ?

There are several problems with your code. On the one hand you have defined a protocol with an associated type. However, you define your createMe() method as a generic which uses some other type. I don't think that was your intent. I think your intent was to have a createMe() method that returns the same type as the protocol's associated type. In this case you need to remove the from the createMe() method. Also, the name createMe() implies that you aren't just returning any type, but the type of the object on which this method is being called. In this case, you don't even need an associated type protocol. You just need a protocol with a Self constraint which allows your code to be a bit simpler. In your Creator's createOne method, your type constraint is more complex than needed.
I think you want the following code:
protocol FooProt {
static func createMe()->Self;
}
struct FooStruct{
}
extension FooStruct: FooProt {
static func createMe() -> FooStruct {
return FooStruct();
}
}
class Creator{
func createOne<T:FooProt>(type: T.Type) -> T {
return T.createMe()
}
}
let foo = Creator().createOne(FooStruct.self)

Here is an alternate solution using an initializer in the protocol instead of a static method.
protocol FooProt {
init()
}
struct FooStruct{
}
extension FooStruct: FooProt {
}
class Creator{
func createOne<T:FooProt>(type: T.Type) -> T {
return T.init()
}
}
let foo = Creator().createOne(FooStruct.self)

Related

Swift protocols and equatable

I'm still learning how to work with arrays of objects implementing protocols with associated types.
I have the following protocols:
public protocol Word : Equatable, Hashable { // compiles
associatedtype WordType : Equatable
var moreWords: [WordType] { get }
}
public protocol WordDataSource { // compiles
associatedtype SomeWord : Word
func findWord(spelling: String) -> SomeWord?
}
I have WordA, WordB and WordC all implementing Word and subclassing NSObject
Basically, I want to implement the datasource protocol using different kinds of class implementing the Word class. This is the kind of code I would like to write, but obviously it doesn't compile.
class MyDataSource : WordDataSource {
func findWord(spelling: String) -> SomeWord? {
if conditionA {
return WordA()
}
if conditionB {
return WordB()
}
if conditionA {
return WordC()
}
}
}
Is that even possible in Swift? What should I write to make that work?
Thanks a lot for your help!
This is not possible, and it's not possible for a reason. Let's assume that your class MyDataSource does compile. Now, we could write such code:
let fooWord = MyDataSource().findWord(spelling: "Foo") // Would return WordA instance
let barWord = MyDataSource().findWord(spelling: "Bar") // Would return WordB instance
but all we know about those two types is that they are of this SomeWord type. So they should be comparable, since Word is comparable, right?
But they're two completely different types, so how would you know how should they be compared? Take a look at the definition of Equatable protocol:
public static func ==(lhs: Self, rhs: Self) -> Bool
You can only compare two objects of the same type that conform to this protocol.

Calling protocol default implementation from regular method, when protocol has associated type

I have a protocol that has a static method with a default parameter. I want to change the default value in a class that implements the protocol. Essentially doing what is easily done with classes and super.
I only have a solution when the Protocol has no associated type.
The following code works, but as soon as you uncomment the associated type declaration, it doesn't compile.
protocol Protocol {
// associatedtype AssociatedType
}
extension Protocol {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
// Uncommenting the Protocol.AssociatedType causes:
// Protocol can only be used as a generic constraint because it has associated type requirements
(self as Protocol).sayHello(name)
}
}
Class<()>().sayHello()
I do understand why it doesn't compile: Protocol has no concrete type for AssociatedType.
So maybe the question should read "Can I explicitly specialize a protocol?", to which I believe the answer is no.
I have a partial workaround. But even when it works, it sucks.
Especially when you consider that I'm writing a library where sayHello is public, so the following workaround forces me to have a second protocol, which has to be public, but is useless.
Here's the workaround:
protocol Parent {}
protocol Protocol: Parent {
associatedtype AssociatedType
}
extension Parent {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
(self as Parent).sayHello(name)
}
}
Class<()>().sayHello()
But this doesn't work for me, because my sayHello uses the associated type. So it can't be extracted to another protocol.
Just to be sure I'm clear, here's what I'd like, only substituting the class for a protocol:
class Protocol<T> {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol<T> {
override func sayHello(name: String = "Stack Overflow") {
super.sayHello(name)
}
}
Class<()>().sayHello()
You're trying to reinvent inheritance in protocols, and there is no such thing. But it is trivial to get what you're talking about; just say what you mean. You don't mean "I want to do the thing I inherited." You mean "I want to do some common behavior." Just provide a name for that common behavior. This removes all ambiguity about which one you mean.
protocol Protocol {
associatedtype AssociatedType
}
extension Protocol {
// Put the default behavior on the protocol, not on the instance
// Of course you could also put it on the instance if that were convenient.
static func defaultSayHello(_ name: String = "World") {
print("Hello, \(name)!")
}
// If you want a default on the instance, too, provide one that we an override
func sayHello(_ name: String = "World") {
Self.defaultSayHello(name)
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello(name: String = "Stack Overflow") {
// Now the default behavior lives on my type
Class.defaultSayHello(name)
}
}
// But other types can get default behavior
class OtherClass<T>: Protocol {
typealias AssociatedType = T
}
Class<()>().sayHello() // Hello, Stack Overflow!
OtherClass<()>().sayHello() // Hello, World!
The one frustrating part about this is that Swift provides no way to limit defaultSayHello to implementers of Protocol. So technically anyone can call it. It can sometimes be worth prefixing it with an _ to indicate that outsiders shouldn't. This is a basic access control problem in protocols, having nothing to do with this specific question; it comes up all the time when you want "things my implementers can use on themselves, but shouldn't be called randomly." Swift doesn't have a solution for that today.
Inspired by Rob Napier's answer, here's what I went with; good old overloading for defaults:
protocol Protocol {
associatedtype AssociatedType
}
extension Protocol {
func sayHello(name: String = "World") {
print("Hello, \(name)!")
}
}
class Class<T>: Protocol {
typealias AssociatedType = T
func sayHello() {
self.sayHello("Stack Overflow")
}
}
Class<()>().sayHello() // Hello, Stack Overflow!
Class<()>().sayHello("you") // Hello, you!
This does fit my needs, but doesn't answer the question. So I'm not 100% satisfied.
I believe Rust gets this one right by allowing traits/protocols to be generic both using X<T> and associated types.

How can I call a static function on a protocol in a generic way?

Is there a point to declaring a static function on a protocol? The client using the protocol has to call the function on a type conforming to the protocol anyway right? That breaks the idea of not having to know the type conforming to the protocol IMO. Is there a way to call the static function on the protocol in a way where I don't have to know the actual type conforming to my protocol?
Nice question. Here is my humble point of view:
Is there a point to declaring a static function on a protocol?
Pretty much the same as having instance methods declared in a protocol.
The client using the protocol has to call the function on a type conforming to the protocol anyway right?
Yes, exactly like instance functions.
That breaks the idea of not having to know the type conforming to the protocol IMO.
Nope. Look at the following code:
protocol Feline {
var name: String { get }
static func createRandomFeline() -> Feline
init()
}
extension Feline {
static func createRandomFeline() -> Feline {
return arc4random_uniform(2) > 0 ? Tiger() : Leopard()
}
}
class Tiger: Feline {
let name = "Tiger"
required init() {}
}
class Leopard: Feline {
let name = "Leopard"
required init() {}
}
let feline: Feline = arc4random_uniform(2) > 0 ? Tiger() : Leopard()
let anotherFeline = feline.dynamicType.createRandomFeline()
I don't know the real type inside the variable feline. I just know that it does conform to Feline. However I am invoking a static protocol method.
Is there a better way to do this?
I see, you would like to call a static method/function declared in a protocol without creating a value that conforms to the protocol.
Something like this:
Feline.createRandomFeline() // DANGER: compiler is not happy now
Honestly I don't know the reason why this is not possible.
yes this is possible:
Swift 3
protocol Thing {
static func genericFunction()
}
//... in another file
var things:[Thing] = []
for thing in things {
type(of: thing).genericFunction()
}
Thank you #appzYourLife for the help! Your answer inspired my answer.
#appzYourLife answered my question. I had an underlying issue I was trying to resolve and the following code resolves my issue, so I'll post this here, maybe it helps someone with my same underlying question:
protocol MyProtocol {
static func aStaticFunc()
}
class SomeClassThatUsesMyProtocolButDoesntConformToIt {
var myProtocolType: MyProtocol.Type
init(protocolType: MyProtocol.Type) {
myProtocolType = protocolType
}
func aFunction() {
myProtocolType.aStaticFunc()
}
}
I created another solution for this case. IMHO this is quite clean and simple.
First, create a protocol for accessing instance type.
protocol TypeAccessible {
func type() -> Self.Type
}
extension TypeAccessible {
func type() -> Self.Type {
return Swift.type(of: self)
}
}
then create your concrete class as here. The point is your protocol should conform to TypeAccessible protocol.
protocol FooProtocol: TypeAccessible {
static func bar()
}
class Foo: FooProtocol {
static func bar() { }
}
On call site use it as
let instance: FooProtocol = Foo()
instance.type().bar()
For further use cases, just make sure your protocols conform to TypeAccessible and that's all.
A little late to the party on this one.
Here's my solution for "adding" static properties/functions/types to a protocol using typealias.
For example:
enum PropertyScope {
case all
case none
}
struct PropertyNotifications {
static var propertyDidChange =
Notification.Name("propertyDidChangeNotification")
}
protocol Property {
typealias Scope = PropertyScope
typealias Notifications = PropertyNotifications
var scope: Scope { get set }
}
Then you can do this anywhere in your code:
func postNotification() {
let scope: Property.Scope = .all
NotificationCenter.post(name: Property.Notifications.propertyDidChange,
object: scope)
}
Using protocols like Java interfaces is rarely a good idea. They are meta types, meant for defining contracts, which is an entirely different kind of thing.
That being said, just for the point of understanding, I find the most simple and effective way for creating the equivalent of a static factory method of a protocol to write a free function.
It should contain the protocol's name, hoping that that will prevent name clashes, and improve discoverability.
In other languages, createP would be a static member of P, named create and be called as P.create(...), which would drastically improve discoverability and guarantee to prevent name clashes.
In swift, though, this is not an option for protocols, so if protocols are for some reason really actually used as a replacement for interfaces, at least including the protocol's name in the function's name is an ugly workaround that's still slightly better than nothing.
P.S. in case the goal is actually to achieve something like an inheritance hierarchy with structs, union style enums are the tool that's meant to serve that purpose :)
protocol P
{
var x: Int { get }
}
func createP() -> P
{
if (todayIsMonday())
{
return A()
}
else
{
return B()
}
}
class A: P
{
var x = 5
}
class B: P
{
var x = 7
}
This isn't an answer so much as it is an extension to the question. Say I have:
#objc public protocol InteractivelyNameable: Nameable {
static func alertViewForNaming(completion:#escaping((_ success: Bool, _ didCancel: Bool, _ error: Error?) -> Void)) -> UIAlertController?
}
And I have a generic view controller that manages various types (generic type is .fetchableObjectType... basically NSFetchResult). I need to check if a specific object type conforms to the protocol, and if so, invoke it.
something like:
// valid swift code
if self.dataSource.fetchableObjectType is InteractivelyNameable {
// not valid swift code
if let alert = (self.dataSource.fetchableObjectType as InteractivelyNameable).alertViewForNaming(....)
}
I had a situation where I need to create same DomainModel object from 2 different response. so this (static method in protocol helped me) approach helped me.
protocol BaseResponseKeyList: CodingKey {
static func getNameKey()->Self
}
enum FirstResponseKeyList: String, BaseResponseKeyList {
case name
func getNameKey()->FirstResponseKeyList {
return .name
}
}
enum SecondResponseKeyList: String, BaseResponseKeyList {
case userName
func getNameKey()->SecondResponseKeyList {
return .userName
}
}
struct MyDomainModel<T:BaseResponseKeyList> : Decodable {
var name:String?
required init(from d:Decoder) {
do {
let container = try d.container(keyedBy:T.self)
name = try container.decode(String.self, forKey:T.getNameKey())
}catch(_) {
print("error")
}
}
}
let myDomainModel = try JSONDecoder().decode(MyDomainModel <FirstResponseKeyList>.self, from: data)
let myDomainModel2 = try JSONDecoder().decode(MyDomainModel <SecondResponseKeyList>.self, from: data2)

Conform to a protocol misunderstanding

class SuperDelegate <T: AnyObject> {
func addDelegate(delegate: T)
{
}
}
My question is about T key, does it mean the same as id in Objective-c? I mean about case of uses.
how to understand the first line class SuperDelegate <T: AnyObject> Sorry I am new in Swift.
As Objective C program for me this line means that we make class to conform a protocol that has to implement all required method. But I don't understand func addDelegate(delegate: T) is this the same like
- (void)addDelegate:(id)delegate which is a property id <T> delegate.
Yes you are correct in your assumptions that AnyObject behaves like id:
You can call any Objective-C method and access any property on an
AnyObject value without casting to a more specific class type. This
includes Objective-C compatible methods and properties marked with the
#objc attribute.
but you have used it here as a generic type rather than as a concrete type that should be cast to. The class is requiring a type that adheres to the AnyObject protocol but it isn't forcing it to be AnyObject (see header files: cmd + click on AnyObject inside Xcode).
So your instance could be instantiated SuperDelegate<AnyObject> but it could also be instantiated SuperDelegate<NSDate>. This means that the whole subset of ObjC methods and properties cannot be guaranteed as they can with a cast to AnyObject as a concrete type because at runtime T might represent NSDate or NSNumber or any other class.
To achieve what you want you would need to write:
class SuperDelegate {
func addDelegate(delegate: AnyObject)
{
}
}
But Swift is a strongly-typed language and it would normally be the case that you had a delegate protocol and that the delegate for your type adhered to the delegate protocol:
protocol DelegateProtocol {
func somethingHappened()
}
struct MyTypeDelegate:DelegateProtocol {
func somethingHappened() {
print("Thanks for telling me!")
}
}
struct MyType {
var delegate:DelegateProtocol?
func tellDelegateSomethingHappened() {
delegate?.somethingHappened()
}
}
let del = MyTypeDelegate()
var type = MyType()
type.delegate = del
type.tellDelegateSomethingHappened()

Wrapping a callback type with Swift protocols

Let's say I'm dealing with a library I don't control and I'm trying to wrap a class that defines a callback type to decouple my code for testing purposes. Here's the class, inside module AXSwift:
public class Application {
public typealias Callback = (element: UIElement) -> ()
public func createObserver(callback: Callback) -> Observer? {
// ...
}
}
Here's the wrapper protocol for testing:
protocol UIElementProtocol {}
extension AXSwift.UIElement: UIElementProtocol {}
protocol ApplicationProtocol {
func createObserver(callback: (element: UIElementProtocol) -> ()) -> Observer?
}
extension AXSwift.Application: ApplicationProtocol {}
I get Type 'Application' does not conform to protocol 'ApplicationProtocol'. If I change UIElementProtocol inside the ApplicationProtocol callback back to UIElement, it works. But UIElement conforms to UIElementProtocol, so why doesn't this work?
Second question: Is there a better way to design the library API to allow for this sort of thing?
The solution was really simple, just implement the protocol in the extension with a method that calls the original method:
extension AXSwift.Application: ApplicationProtocol {
func createObserver(callback: (element: UIElementProtocol) -> ()) -> Observer? {
return createObserver(callback as Callback)
}
}
Where Callback is the expected type. Apparently you have to be explicit about passing a general function type as a more specific type.