Can I use a function with generic type inside a protocol extension of that same type? - swift

I have a protocol :
protocol Repository {
associatedtype Element
func getAll() -> Single<[Element]>
}
And a function using this protocol in a generic way :
class Client {
static func fetchCollection<T: Repository>(of params: T) -> Single<[T.Element]> {
[...]
return sendRequest(of: params)
.flatMap({ (response: HTTPURLResponse, jsonData: Data) -> Single<[T.Element]> in
[...]
})
}
}
It works just fine and is really convenient. The getAll() method I need looks like this in 2 examples :
class TypeARepository: Repository {
typealias Element = TypeA
func getAll() -> Single<[Element]> {
return Client.fetchCollection(of: self)
}
}
class TypeBRepository: Repository {
typealias Element = TypeB
func getAll() -> Single<[Element]> {
return Client.fetchCollection(of: self)
}
}
It works, but it's repetitive.
I would like to put the getAll() function inside a protocol extension because I have many objects implementing Repository and it would be cleaner to write it once.
But it does not work and I cannot find a way to fix it :
extension Repository {
func getAll() -> Single<[Element]> {
return Client.fetchCollection(of: self)
}
}
Type of expression is ambiguous without more context
Here is the error (with my names, I simplified them above) :
Any ideas why ? And can it be fixed ?!

but it's repetitive
I don't think you can do anything about that. They are actually completely different methods because the generic placeholder is resolved differently in each case. Thus you cannot "inject" any common implementation.

Thanks for the help
Working through gists helped me find a solution, it's a good way to work I'm happy to have learned that.
https://gist.github.com/Cocatrix/8660a34b28ccac77a9073b204b2ce933
Actually I simplified my code because the Element property itself had an associated property.
The only missing thing to compile was because I wrote Single<Element> instead of Single<Element.Parsable> in the original question.
The error displayed was not clear and I thought it was something similar to what matt discussed https://stackoverflow.com/a/68578593/7490668
It's resolved.

Related

Swift "nearly matches defaulted requirement"

I have a protocol like this, with some default implementation for the methods:
public protocol BusinessModelTransformable {
func modelId() -> ModelID
func asModelElement(bModel: BusinessModel) -> ModelElement
}
public extension BusinessModelTransformable {
func modelId() -> ModelID { UUID().uuidString }
func asModelElement(bModel: BusinessModel) -> ModelElement {
ModelElement(bModel: bModel, id: self.modelId())
}
}
In another file (of another package if that matters), I do add a conformance to the protocol to a struct, but I don't want the default implement, so I provide my own:
extension ImpDesc: BusinessModelTransformable {
public func modelId() -> ModelID { self.id.uuidString }
public func asModelElement(bModel: BusinessModel) -> ModelElement {
ExtendedModelElement(bModel: bModel,
id: self.id.uuidString,
payload: self)
}
}
I get this warning:
Instance method 'asModelElement(bModel:)' nearly matches defaulted requirement 'asModelElement(bModel:)' of protocol 'BusinessModelTransformable'
only for the asModelElement method.
Why this warning, as this is to me a perfectly valid pattern ?
Why only for the second method ?
how to get rid of that warning () ?
As written by #Joakim Danielson in his comment (many thanks): "while the declarations look the same there is some difference between them", there was indeed a name conflict that was leading to the problem.
Lessons learnt, when the compiler tells you something, that might very well be true.

Why doesn't this behave the way I expect (hope) it would?

I have a several protocols set up in my framework to deal with resources. In one of the protocols, I have set up an extension to provide a default implementation for a decode function. It's simpler to show the code and what happens (see calls to fatalError). There's a lot more code in the actual implementation, but this illustrates the issue:
This is the "base" protocol:
public protocol Resourceful {
associatedtype AssociatedResource
typealias ResourceCompletionHandler = (AssociatedResource?, Error?) -> Void
func fetch(_ completion: #escaping ResourceCompletionHandler)
}
This is a generic, concrete implementaion of Resourceful:
open class WebResourceApiCall<Resource>: Resourceful {
public typealias AssociatedResource = Resource
public typealias FetchedResponse = (data: Data?, urlResponse: URLResponse?)
public init() {
}
public func fetch(_ completion: #escaping ResourceCompletionHandler) {
try! decode(fetched: (data: nil, urlResponse: nil))
}
public func decode(fetched: FetchedResponse) throws -> Resource {
fatalError("It ends up here, but I don't want it to!")
}
}
extension WebResourceApiCall where Resource: Decodable {
public func decode(fetched: FetchedResponse) throws -> Resource {
fatalError("This is where I want it to go...")
}
}
This is how I'm attempting to use it:
public struct Something: Decodable { }
var apiCall = WebResourceApiCall<Something>()
apiCall.fetch { _, _ in } // Implictly calls decode... but not the decode I expected it to! See fatalError() calls...
Instead of calling decode on the extension, like I hoped it would, the "default" decode method with no constraints is always called.
Why doesn't this work the way I expect it to?
Thanks in advance!
Swift is a statically dispatched language, thus the address of the decode() function to be called is computed at compile time, and because the call happens inside the base definition of the class, the compiler picks the original implementation.
Now, if you call the method from a place where the compiler has enough information to pick the implementation you need, it will work:
var apiCall = WebResourceApiCall<Something>()
try apiCall.decode(fetched: (nil, nil))
The above code will call the method from the specialized extension, as at this point the compiler is a better position to know that it has a more specialized implementation to call.
It should be possible to achieve the behaviour you need if you move the decode() method in the dynamic dispatch world - i.e. at the protocol level.

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)

How do you do java equivalent of Generic callback interface in Swift

In java you can declare an interface like this
public interface Foo<T>
{
public void doFoo(T result);
}
And you can use this as a type parameter in another method like this
public void doSomeAsyncTask(final Foo<MyObject> foo)
{
Runnable asyncRunnable = new Runnable()
{
#Override
void run()
{
MyObject result;
// do task to get result
foo.doFoo(result);
}
};
Thread asyncThread = new Thread(asyncRunnable);
asyncThread.start();
}
foo.doFoo(result);
}
As you can see I used the interface for callback from some asynchronous task that runs on a different thread.
UPDATE
Following this guide, I have come up with a solution similar to this
public protocol GenericProtocol {
associatedType T
func magic(result:T)
}
class GenericProtocolThunk<T> : GenericProtocol {
private let _magic : (T)
init<P : GenericProtocol where P.T == T>(_dep : P) {
_magic = p.magic
}
func magic(result: T) {
_magic(result)
}
}
Now in my doSomeAsyncTask method I can just pass GenericProtocolThunk<MyObject> as the parameter type. Is this the right way to achieve what I asked in the question? Honestly it looks quite ugly to me.
I think your problem boils indeed down to what is also noted in the blog post you link to:
"Protocols in Swift can be generic via abstract type members rather
than parameterisation. Consequently, the protocol itself can no longer
be used as a type but only as a generic constraint."
The (ugly) thunk based workaround looks like it solves your problem indeed, although to verify it would help if in your question you used similar terminology for both your Java and Swift examples, and they would be complete, including the type that actually contains the doSomeAsyncTask method to avoid possible confusions.
I can think of a few alternative more Swift friendly solutions if you can change the formulation a bit.
If you could describe Result too with a protocol, then the language isn't fighting against you quite so much. Compared to Java, conforming to a protocol (= implementing an interface) is also not limited to just class types, as shown in the below example so arguably you get a bit more rather out of the language to this end, than in Java:
import Foundation
protocol Result {
// any restrictions on Result that you need.
}
class A:Result { }
struct B:Result { }
enum C:Result { case X }
protocol Foo {
func doFoo(result:Result) -> Void
}
class Bar {
func doSomeAsyncTask(foo:Foo) -> Void {
dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0)) {
foo.doFoo(A())
foo.doFoo(B())
foo.doFoo(C.X)
}
}
}
Another alternative that I've used only recently myself in a related sort of problem is to model result as an enum which enumerates the possible result types, like below (incidentally, each of BibliographyItem, InlineMathFragment, Equation, BlockElement, InlineElement in my code example below are themselves protocols, not concrete types):
public enum Result {
case None
case BibliographyItems([BibliographyItem])
case InlineMathFragments([InlineMathFragment])
case Equations([Equation])
case BlockElements([BlockElement])
case InlineElements([InlineElement])
}
This is handy in a situation where your results come from some already known set of result types, and you commonly end up needing to deal with them in some conditional form.
You may want to simplify it to:
func doSomeAsyncTask<T>(callback: (T)->Void)
Check out this great video:
Rob Napier: Beyond Crusty: Real world protocols

Neat method signature to find subclasses of a given type

I have a method that I have implemented, but am having trouble getting the method signature to be elegant.
The method returns all classes which are a subclass of a specified class. My current method signature looks like :
public func allSubclassesOf(baseClass: AnyClass) -> [AnyClass]
which is fine, apart from the return type being AnyClass which means I always end up with a messy cast like this:
allSubClassesOf(UIView).forEach { (subclass:AnyClass) in
UIView *sigh = subclass as! UIView //!< Gross and unnecessary
...
}
This seems like something that generics should be able to solve :)
Things I've tried :
public func allSubclassesOf<T>() -> [T]
Nope, you're not allowed to add generics to a function like that.
extension NSObject {
class func allSubclasses() -> [Self]
}
Nope, Self isn't available here.
Does anyone know how I can pass a type into this method and have the compiler know what type the returning array would hold; removing the need for a cast?
I am not sure of the implementation of your method but you would need to do something like the following.
What I am doing here is applying a generic type to the method function then saying that I would expect the object type as an argument and return instances of the type in an array.
You could add it as an extension, however without more examples for your code I can't help any further
func subclasses<T>(type: T.Type) -> [T] {
....
}
subclasses(UIView).forEach { (view: UIView) in
print(view)
}