Is it possible to have an array of instances which take a generic parameter without knowing (or caring) what the parameter is? - swift

Consider the following test case, which contains a 'factory' class which is able to call a closure it contains, providing a new instance of some 'defaultable' type:
protocol Defaultable {
init()
}
extension Int: Defaultable { }
extension Double: Defaultable { }
extension String: Defaultable { }
class Factory<T : Defaultable> {
let resultHandler: (T) -> ()
init(resultHandler: (T) -> ()) {
self.resultHandler = resultHandler
}
func callResultHandler() {
resultHandler(T.init())
}
}
Now, this works well when I use it on its own, where I can keep track of the generic type:
// Create Int factory variant...
let integerFactory = Factory(resultHandler: { (i: Int) in print("The default integer is \(i)") })
// Call factory variant...
integerFactory.callResultHandler()
Unfortunately, it doesn't work so well if I want to use factories in a way where I can't keep track of the generic type:
// Create a queue of factories of some unknown generic type...
var factoryQueue = [Factory]()
// Add factories to the queue...
factoryQueue.append(integerFactory)
factoryQueue.append(doubleFactory)
factoryQueue.append(stringFactory)
// Call the handler for each factory...
for factory in factoryQueue {
factory.callResultHandler()
}
I understand the error I get (Generic parameter 'T' could not be inferred), but I don't understand why I can't do this, because when I interact with the array, I don't need to know what the generic parameter is (I don't interact with any of the generic things in the Factory instance). Is there any way I can achieve the above?
Note that the above is a simplified example of what I'm trying to do; in actuality I'm designing a download manager where it can infer what type of file I want (JSON, image, etc.) using generics; the protocol actually contains an init(data:) throws initialiser instead. I want to be able to add the download objects to a queue, but I can't think of any way of adding them to a queue because of the generic nature of the download objects.

The problem is that Swift's strict type safety means you cannot mix two instances of the same class with different generic parameters. They are effectively seen as completely different types.
However in your case, all you're doing is passing a closure to a Factory instance that takes a T input, and then invoking it at any given time with T.init(). Therefore, you can create a closed system in order to contain the type of T, meaning that you don't actually need your generic parameter to be at the scope of your class. You can instead restrict it to just the scope of the initialiser.
You can do this by defining your resultHandler as a Void->Void closure, and create it by wrapping the passed closure in the initialiser with another closure – and then passing in T.init() into the closure provided (ensuring a new instance is created on each invocation).
Now whenever you call your resultHandler, it will create a new instance of the type you define in the closure that you pass in – and pass that instance to the closure.
This doesn't break Swift's type safety rules, as the result of T.init() is still known due to the explicit typing in the closure you pass. This new instance is then being passed into your closure that has a matching input type. Also, because you never pass the result of T.init() to the outside world, you never have to expose the type in your Factory class definition.
As your Factory class itself no longer has a generic parameter, you can mix different instances of it together freely.
For example:
class Factory {
let resultHandler: () -> ()
init<T:Defaultable>(resultHandler: (T) -> ()) {
self.resultHandler = {
resultHandler(T.init())
}
}
func callResultHandler() {
resultHandler()
}
}
// Create Int factory variant...
let integerFactory = Factory(resultHandler: { (i: Int) in debugPrint(i) })
// Create String factory variant...
let stringFactory = Factory(resultHandler: { (i: String) in debugPrint(i) })
// Create a queue of factories of some unknown generic type...
var factoryQueue = [Factory]()
// Add factories to the queue...
factoryQueue.append(integerFactory)
factoryQueue.append(stringFactory)
// Call the handler for each factory...
for factory in factoryQueue {
factory.callResultHandler()
}
// prints:
// 0
// ""
In order to adapt this to take an NSData input, you can simply modify the resultHandler closure & callResultHandler() function to take an NSData input. You then just have to modify the wrapped closure in your initialiser to use your init(data:) throws initialiser, and convert the result to an optional or do your own error handling to deal with the fact that it can throw.
For example:
class Factory {
let resultHandler: (NSData) -> ()
init<T:Defaultable>(resultHandler: (T?) -> ()) {
self.resultHandler = {data in
resultHandler(try? T.init(data:data)) // do custom error handling here if you wish
}
}
func callResultHandler(data:NSData) {
resultHandler(data)
}
}

I recently came back to needing a better answer for this question—as I was performing some refactoring—and thought that it would be really useful to have generic properties of the class, which of course would mean that the class itself would have to be generic as well.
I'm not sure why it didn't occur to me before, but I can simply create a protocol which mirrors the non-generic methods of the class. Using the example I originally had in my question, I could create a FactoryProtocol like so:
protocol FactoryProtocol {
func callResultHandler()
}
Make the class conform to it:
class Factory<T : Defaultable>: FactoryProtocol
And then use the protocol rather than the class when I define my array:
var factoryQueue = [FactoryProtocol]()
This allows me to add any type of specialised Factory to the array and interact with the non-generic methods as I please.

I am afraid this is not possible. The reason for this is that Swift doesn't have first class metatypes. I can imagine all sorts of Monads and Functors being built if this was possible. Unfortunately, this is a limitation. Welcome to Swift.
The golden rule is that in Swift, you cannot nail a type down to a protocol. Swift needs a concrete type.
Check this article out for more details around the subject.

Related

Extension with a generic where clause is not beeing called

The following code works just as expected:
protocol Storeable {
associatedtype Value
func create(value: Value)
}
struct DefaultStore<V>: Storeable {
typealias Value = V
func create(value: V) {
print("base impl. is called with value type: \(String(describing: V.self))")
}
}
class Event {
var title: String = ""
init(title: String) {
self.title = title
}
}
extension DefaultStore where Value: Event {
func create(value: V) {
print("event impl. is called with event: \(value.title)")
}
}
DefaultStore().create(value: Event(title: "Dance Party"))
// prints "event impl. is called with event: Dance Party"
DefaultStore().create(value: "a string object")
// prints "base impl. is called with value of type: String"
Basically I call a function on the generic class DefaultStore and the compiler calls the correct implementation depending on the underlying type.
Now I have a scenario where I want the exact same thing except, that it is wrapped in another object called Wrapper:
struct Wrapper<StoreType: Storeable,ValueType> where StoreType.Value == ValueType {
let store: StoreType
func create(value: ValueType) {
store.create(value: value)
}
}
let defaultStore = DefaultStore<Event>()
let wrapper = Wrapper(store: defaultStore)
wrapper.create(value: Event(title: "Düsseldorfer Symphoniker"))
// prints: "base impl. is called with value of type: Event"
Here I expect that the extension for Event is called but instead the base implementation is called. Anyone any idea what I am doing wrong?
--
Update:
#matt was guessing that there might be a compile time issue: "without the wrapper when you say DefaultStore().create... the Event info can be read all the way back to the DefaultStore generic parameterized type. But in your wrapper the DefaultStore is created first so it is the general type and that's all it is."
I believe that is not the case because you can also create the DefaultsStore first and it's still working without the Wrapper. Also the compiler warns me if the types don't match.
Nothing to do with "wrappers".
You seem to think that a where extension on a generic struct is a kind of substitute for some sort of dynamic dispatch, i.e. we're going to wait until runtime, look to see what kind of object the parameter to create really is, and dispatch accordingly. That's not how it works. Everything has to be resolved at compile time. At compile time, what we know is that you are not calling create with an Event — you are calling it with a ValueType. So it passes into the create with generic V.
So, for example:
struct Wrapper {
let store: DefaultStore<Event>
func create(value: Event) {
store.create(value: value)
}
}
That works the way you have in mind because we are exposing the fact that this is an Event as far as the DefaultStore is concerned at the point of calling create.
That's just a guess at what your confusion is.
Another possibility is you might imagine that the generic resolution of ValueType somehow "leaks" up to the resolution of V, but that's not true either.
Yet another possibility is you might suppose that a DefaultStore<Event> is a subtype of DefaultStore<Storable> or similar, as if there were dynamic dispatch for parameterized types, but that is exactly what is not the case. Everything has to be known completely at compile time at the call site.

Swift: casting un-constrained generic type to generic type that confirms to Decodable

Situation
I have a two generic classes which will fetch data either from api and database, lets say APIDataSource<I, O> and DBDataSource<I, O> respectively
I will inject any of two class in view-model when creating it and view-model will use that class to fetch data it needed. I want view-model to work exactly same with both class. So I don't want different generic constraints for the classes
// sudo code
ViewModel(APIDataSource <InputModel, ResponseModel>(...))
// I want to change the datasource in future like
ViewModel(DBDataSource <InputModel, ResponseModel>(...))
To fetch data from api ResponseModel need to confirms to "Decodable" because I want to create that object from JSON. To fetch data from realm database it need to inherit from Object
Inside ViewModel I want to get response like
// sudo code
self.dataSource.request("param1", "param2")
If developer tries to fetch api data from database or vice-versa it will check for correct type and throws proper error.
Stripped out version of code for playground
Following is stripped out version of code which shows what I want to achieve or where I am stuck (casting un-constrained generic type to generic type that confirms to Decodable)
import Foundation
// Just to test functions below
class DummyModel: Decodable {
}
// Stripped out version of function which will convert json to object of type T
func decode<T:Decodable>(_ type: T.Type){
print(type)
}
// This doesn't give compilation error
// Ignore the inp
func testDecode<T:Decodable> (_ inp: T) {
decode(T.self)
}
// This gives compilation error
// Ignore the inp
func testDecode2<T>(_ inp: T){
if(T.self is Decodable){
// ??????????
// How can we cast T at runtime after checking T confirms to Decodable??
decode(T.self as! Decodable.Type)
}
}
testDecode(DummyModel())
Any help or explanation that this could not work would be appreciated. Thanks in advance :)
As #matt suggests, moving my various comments over to an answer in the form "your problem has no good solution and you need to redesign your problem."
What you're trying to do is at best fragile, and at worst impossible. Matt's approach is a good solution when you're trying to improve performance, but it breaks in surprising ways if it impacts behavior. For example:
protocol P {}
func doSomething<T>(x: T) -> String {
if x is P {
return "\(x) simple, but it's really P"
}
return "\(x) simple"
}
func doSomething<T: P>(x: T) -> String {
return "\(x) is P"
}
struct S: P {}
doSomething(x: S()) // S() is P
So that works just like we expect. But we can lose the type information this way:
func wrapper<T>(x: T) -> String {
return doSomething(x: x)
}
wrapper(x: S()) // S() simple, but it's really P!
So you can't solve this with generics.
Going back to your approach, which at least has the possibility of being robust, it's still not going to work. Swift's type system just doesn't have a way to express what you're trying to say. But I don't think you should be trying to say this anyway.
In the method that fetch data I will check type of generic type and if it confirms to "Decodable" protocol I will use it to fetch data from api else from database.
If fetching from the API vs the database represents different semantics (rather than just a performance improvement), this is very dangerous even if you could get it to work. Any part of the program can attach Decodable to any type. It can even be done in a separate module. Adding protocol conformance should never change the semantics (outwardly visible behaviors) of the program, only the performance or capabilities.
I have a generic class which will fetch data either from api or database
Perfect. If you already have a class, class inheritance makes a lot of sense here. I might build it like:
class Model {
required init(identifier: String) {}
}
class DatabaseModel {
required init(fromDatabaseWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromDatabaseWithIdentifier: identifier )}
}
class APIModel {
required init(fromAPIWithIdentifier: String) {}
convenience init(identifier: String) { self.init(fromAPIWithIdentifier: identifier )}
}
class SomeModel: DatabaseModel {
required init(fromDatabaseWithIdentifier identifier: String) {
super.init(fromDatabaseWithIdentifier: identifier)
}
}
Depending on your exact needs, you might rearrange this (and a protocol might also be workable here). But the key point is that the model knows how to fetch itself. That makes it easy to use Decodable inside the class (since it can easily use type(of: self) as the parameter).
Your needs may be different, and if you'll describe them a bit better maybe we'll come to a better solution. But it should not be based on whether something merely conforms to a protocol. In most cases that will be impossible, and if you get it working it will be fragile.
What you'd really like to do here is have two versions of testDecode, one for when T conforms to Decodable, the other for when it doesn't. You would thus overload the function testDecode so that the right one is called depending on the type of T.
Unfortunately, you can't do that, because you can't do a function overload that depends on the resolution of a generic type. But you can work around this by boxing the function inside a generic type, because you can extend the type conditionally.
Thus, just to show the architecture:
protocol P{}
struct Box<T> {
func f() {
print("it doesn't conform to P")
}
}
extension Box where T : P {
func f() {
print("it conforms to P")
}
}
struct S1:P {}
struct S2 {}
let b1 = Box<S1>()
b1.f() // "it conforms to P"
let b2 = Box<S2>()
b2.f() // "it doesn't conform to P"
This proves that the right version of f is being called, depending on whether the type that resolves the generic conforms to the protocol or not.

Difference between using Generic and Protocol as type parameters, what are the pros and cons of implement them in a function

Since Swift allows us using both Protocol and Generic as parameter types in a function, the scenario below has come into my mind:
protocol AProtocol {
var name: String{ get }
}
class ClassA: AProtocol {
var name = "Allen"
}
func printNameGeneric<T: AProtocol>(param: T) {
print(param.name)
}
func printNameProtocol(param: AProtocol) {
print(param.name)
}
The first function uses generic as parameter type with a type constraint, and the second function uses protocol as the parameter type directly. However, these two functions can have the same effect, which is the point confusing me. So my questions are:
What are the specific scenarios for each of them (or a case which can only be done by the specific one, but not another)?
For the given case, both functions turn out the same result. Which one is better to implement (or the pros and cons of each of them)?
This great talk has mentioned generic specialization, which is a optimization that turn the way of function dispatching from dynamic dispatching (function with non-generic parameters) to static dispatching or inlining (function with generic parameters). Since static dispatching and inlining are less expensive in contrast with dynamic dispatching, to implement functions with generic can always provide a better performance.
#Hamish also gave great information in this post, have a look for more information.
Here is a new question came to me:
struct StructA: AProtocol {
var a: Int
}
struct StructB: AProtocol {
var b: Int
}
func buttonClicked(sender: UIButton) {
var aVar: AProtocol
if sender == self.buttonA
{
aVar = StructA(a: 1)
}
else if sender == self.buttonA
{
aVar = StructB(b: 2)
}
foo(param: aVar)
}
func foo<T: AProtocol>(param: T) {
//do something
}
If there are several types conform to a Protocol, and are pass in to a generic function in different conditions dynamically. As shown above, pressing different buttons will pass different types(StructA or StructB) of parameter into function, would the generic specialization still work in this case?
There is actually a video from this year's WWDC about that (it was about performance of classes, structs and protocols; I don't have a link but you should be able to find it).
In your second function, where you pass a any value that conforms to that protocol, you are actually passing a container that has 24 bytes of storage for the passed value, and 16 bytes for type related information (to determine which methods to call, ergo dynamic dispatch). If the passed value is now bigger than 24 bytes in memory, the object will be allocated on the heap and the container stores a reference to that object! That is actually extremely time consuming and should certainly be avoided if possible.
In your first function, where you use a generic constraint, there is actually created another function by the compiler that explicitly performs the function's operations upon that type. (If you use this function with lots of different types, your code size may, however, increase significantly; see C++ code bloat for further reference.) However, the compiler can now statically dispatch the methods, inline the function if possible and does certainly not have to allocate any heap space. Stated in the video mentioned above, code size does not have to increase significantly as code can still be shared... so the function with generic constraint is certainly the way to go!
Now we have two protocol below:
protocol A {
func sometingA()
}
protocol B {
func sometingB()
}
Then the parameter need to conform to both A and B.
//Generic solution
func methodGeneric<T:A>(t:T)where T:B {
t.sometingA()
t.sometingB()
}
//we need protocol C to define the parameter type
protocol C:A,B {}
//Protocol solution
func methodProtocol(c:C){
c.sometingA()
c.sometingB()
}
It seems that nothing is wrong but when we define a struct like this:
struct S:A,B {
func sometingB() {
print("B")
}
func sometingA() {
print("A")
}
}
The methodGeneric works but we need to change struct S:A,B to struct S:C to make methodProtocol work. Some questions:
Do we really need protocol C?
Why not would we write like func method(s:S)?
You could read more about this in the Generic Doc for additional information .

Parameterizing closures as generic based on parameter-list/return type

Is there a way to make a generic type signature for a closure such that I can later call it generically? In particular my question is how to deal with an unknown number of arguments.
I have an object that I’d like to call a series of closures on an update, and I’d like other objects to be able to register closures that they’d like to be called with that first object.
Closures aren’t hashable, but I’d like to be able to also unregister a closure, so I wound up creating a custom type to handle this based on a dictionary:
//T is the block signature such as Double->()
struct ClosureCollection<T> : SequenceType {
private var idx=0
var closureDict:[Int:(T,NSOperationQueue)]=[:]
mutating func addClosure(b:T) -> Int {
return addClosure(NSOperationQueue.mainQueue(),b)
}
mutating func addClosure(q:NSOperationQueue, _ b:T) -> Int {
closureDict[idx]=(b,q)
idx+=1
return idx-1
}
mutating func dropClosure(k:Int) {
closureDict.removeValueForKey(k)
}
func generate() -> AnyGenerator<(T,NSOperationQueue)> {
var dgen=closureDict.generate()
return AnyGenerator {
return dgen.next()?.1
}
}
}
This lets me use the collection in code like this:
Declare it:
private var distributionPoints=ClosureCollection<(CMDeviceMotion?,NSError?) -> ()> ()
Use it:
for (p,q) in distributionPoints {
q.addOperationWithBlock {p(dm,error)}
}
So far, all’s good but it requires the caller to follow a pretty specific pattern to use the collection that I'd like to hide. I’d like to extend this idea to where I can ask the collection to run the for loop itself using syntax something like
distributionPoints.runAllWith(dm,error)
The problem is with the runAllWith signature-- my current implementation is generic over the full closure signature because I don't know how to make the number of arguments to the closure generic. I suspect this can be done if I know the blocks accept one argument and return one argument, for example, by using two type placeholders, say T for the argument and U for the return value.
What I don’t seem able to do is make this generic across an unknown number of parameters. The type I’m creating doesn’t care what the structure of the block is, it just wants to accept closures with a certain signature and then provide a mechanism to call them by exposing an API that depends on the closure signature.
I don’t think there’s support for variadic generic parameters, so I can’t go down that road. Tuple-splat was deprecated.
Is there a way to do this without requiring the caller to bundle arguments into a tuple and then requiring a wrapper around each closure to unwrap a tuple of arguments and do a hand-crafted tuple splat?

Pass only specific types as argument to function

I have a function which is being repeated about 8-9 times and I'm trying to cut down on redundancy.Is it possible to create a function which take spefic types and returns an array of the initlizated type using the json object being sent.
Current function
static func initArray(json: JSON)-> [Event]{
var array = [Event]()
json.forEach(){
array.append(Event.init(json: $0.1))
}
return array
}
Desired function
static func initArray<T> (type: T, json: JSON)-> [T]{
var array = [T]()
//I get stuck here im not too sure how to initlize the type
//Thats why im wondering if it's possible to pass speific types
//to the function
return array
}
You initialize an instance of T just like an instance of any known class, with whatever initializers are available to it. To know what your options are, you generally need to constraint T in some form. The way I typically go about this is to define a protocol that all the types I care about passing to the function adopt. In your case you would put specific initializers in your protocol. Then constraint T to be of that type:
protocol SomeProtocol {
init(json: JSON)
}
class someClass {
static func initArray<T:SomeProtocol>(type: T, json: JSON) -> [T] {
// Create your objects, I'll create one as an example
let instance = T.init(json: json)
return [instance]
}
}
Constraining generic types can be more complex than what I've shown, so I'd recommend checking out the Type Constraints section of the Generics chapter of The Swift Programming Language for more information.