Array of slightly different generics - swift

I have a class that takes a generic type, which must inherit from class WorldObject:
class WorldObjectsProvider<WorldObjectType: WorldObject>
This class will be creating objects of class WorldObjectType and return them in one function. Now I would like to create an array of such classes (WorldObjectsProvider), but I want this array to be able to keep many different types of generic classes WorldObjectsProvider, for example:
class TestObject: WorldObject { }
let providers: [WorldObjectsProvider<WorldObject>] = [WorldObjectsProvider<WorldObject>(), WorldObjectsProvider<TestObject>()]
In general I think this might be possible, as all generic types are supposed to inherit from WorldObject. This could work by returning all values as references to base class WorldObject. But I guess this might be too much for generics. Is there some way to create such an array?

Swift generic types are invariant in respect to their generic arguments, which means that MyGeneric<A> is incompatible with MyGeneric<B>, even if A: B.
This being said, if you need to use two different generics, you need a common denominator for the two generics. A type eraser is one of the possible solutions:
struct AnyProvider<T: WorldObject> {
init<U: WorldObject>(_ provider: WorldObjectsProvider<U>) { }
}
let providers: [AnyProvider<WorldObject>] = [AnyProvider(WorldObjectsProvider<WorldObject>()), AnyProvider(WorldObjectsProvider<TestObject>())]
This will allow you to use multiple types of generics in the same collections, provided they have a common ground. The downside is the fact that the type eraser will likely have to mimic and forward all public methods of the original type.
For example, if the original provider has a func someProviderMethod() method, then AnyProvider will also have to declare it:
struct AnyProvider<T: WorldObject> {
private let _someProviderMethod: () -> Void
init<U: WorldObject>(_ provider: WorldObjectsProvider<U>) {
_someProviderMethod = provider.someProviderMethod
}
func someProviderMethod() {
_someProviderMethod()
}
}

Related

Swift Generics - Attempting to make a generic protocol concrete fails when attempting to use specialised sub-protocol as variable

I want to know why my SomeResourceRepository is still generic, even though it is only defined in one case only, which is when I set ResourceType = SomeResource, which XCode formats as below with the where clause. Code below which shows the exact setup I'm trying to achieve, written in a Playground.
I am trying to define a generic protocol for any given ResourceType such that the ResourceTypeRepository protocol then automatically requires the same set of functions, without having to copy-paste most of GenericRepository only to manually fill in the ResourceType for each Repository I make. The reason I need this as a protocol is because I want to be able to mock this for testing purposes later. So I'll provide an implementation of said protocol somewhere else in the actual app.
My interpretation of the code below is that it should work, because both SomeResourceLocalRepository and SomeResourceRemoteRepository are concrete, as I have eliminated the associated type by defining them "on top of" SomeResourceRepository, which is only defined where ResourceType == SomeResource.
import Foundation
struct SomeResource: Identifiable {
let id: String
let name: String
}
struct WhateverResource: Identifiable {
let id: UUID
let count: UInt
}
protocol GenericRepository: class where ResourceType: Identifiable {
associatedtype ResourceType
func index() -> Array<ResourceType>
func show(id: ResourceType.ID) -> ResourceType?
func update(resource: ResourceType)
func delete(id: ResourceType.ID)
}
protocol SomeResourceRepository: GenericRepository where ResourceType == SomeResource {}
protocol SomeResourceLocalRepository: SomeResourceRepository {}
protocol SomeResourceRemoteRepository: SomeResourceRepository {}
class SomeResourceLocalRepositoryImplementation: SomeResourceLocalRepository {
func index() -> Array<SomeResource> {
return []
}
func show(id: String) -> SomeResource? {
return nil
}
func update(resource: SomeResource) {
}
func delete(id: String) {
}
}
class SomeResourceService {
let local: SomeResourceLocalRepository
init(local: SomeResourceLocalRepository) {
self.local = local
}
}
// Some Dip code somewhere
// container.register(.singleton) { SomeResourceLocalRepositoryImplementation() as SomeResourceLocalRepository }
Errors:
error: Generic Protocols.xcplaygroundpage:45:16: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
let local: SomeResourceLocalRepository
^
error: Generic Protocols.xcplaygroundpage:47:17: error: protocol 'SomeResourceLocalRepository' can only be used as a generic constraint because it has Self or associated type requirements
init(local: SomeResourceLocalRepository) {
I will probably have to find another way to accomplish this, but it is tedious and quite annoying as we will produce a lot of duplicate code, and when we decide to change the API of our repositories, we will have to manually change it for all the protocols as we don't follow a generic "parent" protocol in this work-around.
I have read How to pass protocol with associated type as parameter in Swift and the related question found in an answer to this question, as well as Specializing Generic Protocol and others.
I feel like this should work, but it does not. The end goal is a concrete protocol that can be used for dependency injection, e.g. container.register(.singleton) { ProtocolImplementation() as Protocol } as per Dip - A simple Dependency Injection Container, BUT without copy-pasting when the protocol's interface clearly can be made generic, like in the above.
As swift provides a way to declare generic protocols (using associatedtype keyword) it's impossible to declare a generic protocol property without another generic constraint. So the easiest way would be to declare resource service class generic - class SomeResourceService<Repository: GenericRepository>.
But this solution has a big downside - you need to constraint generics everywhere this service would be involved.
You can drop generic constraint from the service declaration by declaring local as a concrete generic type. But how to transit from generic protocol to the concrete generic class?
There's a way. You can define a wrapper generic class which conforms to GenericRepository. It does not really implements its methods but rather passes to an object (which is real GenericRepository) it wraps.
class AnyGenericRepository<ResourceType: Identifiable>: GenericRepository {
// any usage of GenericRepository must be a generic argument
init<Base: GenericRepository>(_ base: Base) where Base.ResourceType == ResourceType {
// we cannot store Base as a class property without putting it in generics list
// but we can store closures instead
indexGetter = { base.index() }
// and same for other methods or properties
// if GenericRepository contained a generic method it would be impossible to make
}
private let indexGetter: () -> [ResourceType] {
indexGetter()
}
// ... other GenericRepository methods
}
So now we have a concrete type which wraps real GenericRepository. You can adopt it in SomeResourceService without any alarm.
class SomeResourceService {
let local: AnyGenericRepository<SomeResource>
}

Cannot convert swift generic subclass to generic superclass

I want to write better and cleaner code using parametrized classes in Swift but I'm getting a strange build error:
Cannot convert value of type 'CustomAdapter' to expected argument type 'TableTestParametrizedAdapter<ETableViewCell>'
What I actually want is to be able to create a base adapter class with one method (overridden in adapter subclasses) used to bind cell subclasses with the corresponding data model and get rid of casting every time.
I'll post the code below, in order to understand better what I mean.
class TestParametrizedAdapter<C>: NSObject {
func doSmth(cell: C) {
}
}
class TableTestParametrizedAdapter<C>: TestParametrizedAdapter<C> where C:ETableViewCell {
}
class PeopleTableViewCell: ETableViewCell {
}
class CustomAdapter: TableTestParametrizedAdapter<PeopleTableViewCell> {
override func doSmth(cell: PeopleTableViewCell) {
}
}
class TestBaseController: UIViewController {
var adapter: TableTestParametrizedAdapter<ETableViewCell>?
override func viewDidLoad() {
super.viewDidLoad()
setAdapter(adapter: CustomAdapter()) // this is the line with build error
}
func setAdapter(adapter: TableTestParametrizedAdapter<ETableViewCell>) {
self.adapter = adapter
}
}
I have read on some other posts about this and there was pointed out that GenericClass<B> and GenericClass<A> are completely unrelated even if B is a subclass of A, hence you cannot cast one to the other. (https://stackoverflow.com/a/50859053/10115072)
Anywat, are there any solutions for this? How can we use the power of parametrization of Swift in this case? I use Swift 4.
Thanks in advance.
Even if Swift would support variance in custom generics your code would be wrong, since you try to use object that can only handle PeopleTableViewCell instances in place of object that can handle any ETableViewCell. If that is indeed what you want and you don't mind some run-time checks you can do something similar with little type erasure:
class TestAnyAdapter: NSObject {
func doSmth(cell: Any) {}
}
class TableTestParametrizedAdapter<C>: TestAnyAdapter where C:ETableViewCell {
override func doSmth(cell: Any) {
guard let cell = cell as? C else {
return
}
self.doSmth(cell: cell)
}
func doSmth(cell: C) {}
}
the rest of the code will be the same as you already have, only without compile-time error.
I agree with Konstantin about the fundamental problem here. This code is simply incorrect, and Swift is telling you so. CustomAdapter.doSmth cannot accept any arbitrary ETableViewCell, but adapter claims it must.
There are many solutions, depending on the actual problem you're trying to solve. You indicated you want to write "better and cleaner code." That suggests you have existing code where you're finding excessive duplication or casting. So what you want to do is look at that code, and see what code is being duplicated, and then we can help you design generic solutions to avoid that duplication. There is no universal answer to this question; abstraction choices you make in one direction will make other directions less flexible. Abstraction is choices; they need to be made in context.
As a rule in Swift, you should avoid relying on subclassing. There is some that is required, because of bridging to ObjC, but Swift-focused code should avoid subclasses. In your particular example, the interesting class has just one function. If that's really true, then implementing it is easy. Use one function:
func customAdapter(cell: PeopleTableViewCell) {}
class TestBaseController: UIViewController {
let adapter: (PeopleTableViewCell) -> Void = customAdapter
}
"But my real problem is more complex than that!" Ok. Then we have to talk about your real problem. Abstracting these things down to their simplest forms rightly should lead to the simplest solutions. If things are actually a bit more complex, you could use a struct and a protocol.
protocol Adapter {
associatedtype Cell: UITableViewCell
func doSmth(cell: Cell)
}
struct CustomAdapter<Cell: ETableViewCell>: Adapter {
func doSmth(cell: Cell) {}
}
class TestBaseController: UIViewController {
let adapter: CustomAdapter<PeopleTableViewCell> = CustomAdapter()
}
I'm glossing over what may be your question, which is how to make a function that only accepts PeopleTableViewCell be used where a function that accepts any ETableViewCell is required. That's impossible. It's not a limitation in Swift; it's just type-wise impossible. The best you could do is add "do nothing" or "crash" as Konstantin explains.
If you can nail down a little more what particular problem in your existing code you're trying to fix, we can probably help you design better solutions. Adding generics does not make your code "better or cleaner" by themselves (and most of the best solutions barely need generics at all in my experience).
Let's try to get some facts straight.
Let's say we have generic class C<T>.
And let's also say we have classes D and D2, where D2 is the subclass of T.
Then C<D2> is not a subclass of C<D>. They are just separate types. (We say there is not covariance.)
Let's say our generic class C<T> has a subclass C2<T>.
Then C2<D> is a subclass of C<D>, and C2<D2> is a subclass of C<D2>.
So as long as the parameterized types are the same, there's polymorphism. But there's no covariance if the parameterized types are different, even if parameterized types are class and subclass.
(Swift Optional and Swift collections get a special covariance dispensation here, but that's baked into the language; you can't the same dispensation.)

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 .

implicitly convert between two 'identical' types in swift

If I have two types
struct PersonFromLibraryA {
let name: String
let age: Int
}
struct PersonFromLibraryB {
let name: String
let age: Int
}
Is there a way to implicitly be able to pass an A into a method which is expecting a B?
func doSomething(withPerson person: PersonFromLibraryA) {
...
}
let person = PersonFromLibraryB(name: "Alice", age: 42)
doSomething(withPerson: person))
I'd expect this to be type safe i.e. if A or B diverge in any way whatsoever, this shouldn't compile.
I have about 20 or so of this situation (I'm mapping between layers of abstraction in a library) and am getting very tired of filling files with boilerplate mapping methods!
I suspect I already know the answer to this question, but I figure I'll ask it here just to be sure!
Agreed with rmaddy that the one way to fix this w/ type-saftey is protocol (without type-safety, you can do it with unsafeBitCast, but please don't do that). This raises a warning flag, though, that you may have over-abstracted something (or more likely: abstracted along the wrong axis) if you have many types that are identical but distinct between layers.
I believe you should think OOP as Swift is an OOP language. Change both into classes. Generally, you can do this by simply changing the word struct to class. Then create a new class.
class PersonFromLibrary {
let name: String
let age: Int
}
Now setup your other classes:
class PersonFromLibraryA: PersonFromLibrary {
}
class PersonFromLibraryB: PersonFromLibrary {
}
Now instead of using PersonFromLibraryA as the parameter type use PersonFromLibrary. Now you can pass all of the PersonFromLibraryA type things as PersonFromLibrary. The only restriction here is that if you add any unique qualities to any of the PersonFromLibraryA level classes you will have to cast it back to PersonFromLibraryA or it's corresponding class in order to use its unique properties.