Generics Protocol as Type in Swift - swift

How I can create a protocol variable. My goal is a protocol will be have a function with a generic type and I'm using associatedtype which is accessing to Class and the function will be return generic type. Example declaration below:
public protocol ComponentFactory {
associatedtype T // A class and that class can be inherit from another so I need define generic type here
func create() -> T
}
I want to declare a variable for this protocol like that:
fileprivate var mComponentFactoryMap = Dictionary<String, ComponentFactory>()
At this line I receive a error:
Protocol 'ComponentFactory' can only be used as a generic constraint because it has Self or associated type requirements
I see from Android, actually from kotlin they have a declare for interface like:
private val mComponentFactoryMap = mutableMapOf<String, ComponentFactory<*>>()
Any guys can help me, how I can declare this from Swift?

I've solved this from few months ago with descriptions below. Please check it and give me another solution if you have.
Firstly, make some change for Protocol. At associatedtype T should be change to associatedtype Component and Component is a class which will be inherited from another class (important step).
public protocol ProComponentFactory {
associatedtype Component
func create() -> Component?
}
Second, I will make a Generic Struct with inheritance from ProComponentFactory:
public struct ComponentFactory<T>: ProComponentFactory {
public typealias Component = T
public func create() -> T? { return T.self as? T }
}
Well done, for now you can define a variable as I example in my question above:
fileprivate var mComponentFactoryMap = Dictionary<String, ComponentFactory<Component>>()
As well for any class was inherit from Component and variable mComponentFactoryMap can using extension inside.

Related

Create interface with generic types

I'm trying to create public interface for my class operating on generics.
I've created interface
public protocol StorageProtocol {
associatedtype StorageObject: Codable
func store(storeObject: StorageObject)
func get() -> StorageObject?
}
and implementation
public class Storage<T: Codable>: StorageProtocol {
public func store(storeObject: T) {}
public func get() -> T?
Now, when I try to create instance it forces me any keyword
let myStorage: any StorageProtocol = Storage<Credentials>()
and I can't call storage.store(storeObject: Credentials()) as I'm getting error:
Associated type 'StorageObject' can only be used with a concrete type or generic parameter base.
What I'm missing here?
The compiler does not know what type to require in the parameter storeObject when you constrain myStorage to be any StoreageProtocol, as the generic StorageObject could be any Codable object. A workaround could be to explicitly add a parameter for the type of the generic.
public protocol StorageProtocol<StorageObject> { // add a generic parameter
associatedtype StorageObject: Codable
func store(storeObject: StorageObject)
func get() -> StorageObject?
}
and then when you define the variable
let myStorage: any StorageProtocol<Credentials> = Storage<Credentials>()
Then the compiler will know you want to store Credentials for this variable and allow you to call store as you specialized the protocol to the correct type.

Why can i make same-type requirement in swift with generics? Is there any way?

Ok so i have some class defined like this:
public final class Process<InputType, OutputType, Memory>
And i want to make the function available only for case when InputType and
OutputType are exactly same type.
So i tried like this like this:
extension Process where InputType == OutputType { }
But this would result in:
Same-type requirement makes generic parameters InputType and
OutputType equivalent
So then i've gone a bit far and tried to do it like this:
func bypass<SameType>() -> Process<SameType, SameType, Memory> where OutputType == InputType {}
But this would result in exactly same error.
So the question is why can't i define generics in such way that two generic types would be Equivalent, cause that's exactly what i wanted. I wanted to define function available only for this case, that would fail at compile time if this rule is not followed.
So right now i'm using something like this:
public static func bypass<SameType>() -> Process<SameType, SameType, Memory>
Which would ultimately fail only at runtime and not even when created but when the concrete class is triggered for action.
Is there any way to define extension or function for generic parameters of same type that would just not compile(result in compile time error)?
Update: some details of implementations are missed cause would make code unreadable and they are not critical for the context
In Swift 4 and later, you can write:
public final class Process<InputType, OutputType, Memory> {
// ...
}
extension Process where InputType == OutputType {
func bypass() -> Process<InputType, OutputType, Memory> {
// ...
}
}
Original answer (Swift 3):
You can't constraint types on generic classes yet even though some changes are coming in Swift 4. However, you can constraint types on a protocol. You can make a protocol that only Process conforms to like this:
protocol ProcessProtocol {
// I haven't found a way to name these associated type identically to
// those in the class. If anyone discover a way, please let me know
associatedtype IT
associatedtype OT
associatedtype MT
}
final public class Process<InputType, OutputType, MemoryType>: ProcessProtocol {
typealias IT = InputType
typealias OT = OutputType
typealias MT = MemoryType
// your code
}
// Note that this is an extension on the protocol, not the class
extension ProcessProtocol where IT == OT {
func foo() {
// this function is only available when InputType = OutputType
}
}

Swift: Generic Protocols

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)

Can one Swift typealias be constrained to another in a protocol definition? If not, how else can I achieve something like component registration?

I am writing a small inversion of control container for my own little framework in swift (mainly so I can learn more) and I have stumbled across a problem - well, several problems of which this is just the latest.
I had hoped that swift would be flexible enough for me to port the core patterns of Castle.Core in C#. My first disappointment was in the weak reflection capabilities provided by Apple, which led me to do this ugliness...
public protocol ISupportInjection {
}
public protocol IConstructorArguments {
func toArgumentsDictionary() -> [String:AnyObject?]
}
public protocol ISupportConstructorInjection: ISupportInjection {
init(parameters:IConstructorArguments)
}
...the idea being that someday (soon) I could deal with it and remove any reference to these constraints in my services/components.
Now I want to write IIocRegistration with two typealias: one for the TService and the other for the TComponent, ideally where TService is a protocol and TComponent is a concrete struct or class that implements TService:
public protocol IIocRegistration {
typealias TService: Any
typealias TComponent: TService, ISupportConstructorInjection
}
But it seems that TComponent: TService is totally invalid according to the compiler, which says:
Inheritance from non-protocol, non-class type '`Self`.TService'
So I am wondering how to make a typealias derive another typealias if it possible.
First of all what typealias do inside a swift protocol is not to define a type alias. The keyword typealias inside swift protocol is used to define associated type about which you can check out the swift programming book.
Back to your situation the possible solution I can come up with is move the typealias outside protocol like such
public typealias TService = Any
public struct component: TService, ISupportConstructorInjection {
public init(parameters: IConstructorArguments) {
//
}
}
public typealias TComponent = component
public protocol IIocRegistration {
var service: TService {get set}
var component: TComponent {get set}
}

Statically typed properties in Swift protocols

I'm trying to use Protocol-Oriented Pgrogramming for model layer in my application.
I've started with defining two protocols:
protocol ParseConvertible {
func toParseObject() -> PFObject?
}
protocol HealthKitInitializable {
init?(sample: HKSample)
}
And after implementing first model which conforms to both I've noticed that another model will be basically similar so I wanted to create protocol inheritance with new one:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
var value: AnyObject { get set }
}
A you can see this protocol has one additional thing which is value but I want this value to be type independent... Right now I have models which use Double but who knows what may show up in future. If I leave this with AnyObject I'm sentenced to casting everything I want to use it and if I declare it as Double there's no sense in calling this BasicModel but rather BasicDoubleModel or similar.
Do you have some hints how to achieve this? Or maybe I'm trying to solve this the wrong way?
You probably want to define a protocol with an "associated type",
this is roughly similar to generic types.
From "Associated Types" in the Swift book:
When defining a protocol, it is sometimes useful to declare one or
more associated types as part of the protocol’s definition. An
associated type gives a placeholder name (or alias) to a type that is
used as part of the protocol. The actual type to use for that
associated type is not specified until the protocol is adopted.
Associated types are specified with the typealias keyword.
In your case:
protocol BasicModel: HealthKitInitializable, ParseConvertible {
typealias ValueType
var value: ValueType { get set }
}
Then classes with different types for the value property can
conform to the protocol:
class A : BasicModel {
var value : Int
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
class B : BasicModel {
var value : Double
func toParseObject() -> PFObject? { ... }
required init?(sample: HKSample) { ... }
}
For Swift 2.2/Xcode 7.3 and later, replace typealias in the
protocol definition by associatedtype.