Partial function application with generics - ios

I'm working with an Observer API (ObserverSet) which have the following function :
public func add<T: AnyObject>(object: T, _ f: T -> Parameters -> Void) -> ObserverSetEntry<Parameters>
It simply register an object then call the instance method f on the object when notification triggers
In one of my manager, I need to hide the previous function with one of mine so I can force an observer to call a predefine function implemented via a protocol.
Here's what I've done so far :
#objc protocol Observer : NSObjectProtocol {
func observe(param: String) -> Void
}
func addObserver<T: AnyObject where T: Observer>(observer: T) {
let f: T -> String -> Void = observer.dynamicType.observe
entries.addObserver(observer, f)
}
Unfortunately, I have the following error showing up Partial application of generic method is not allowed
I've found a possible workaround somewhere on SO which look like that :
let f: T -> String -> Void = { (obs: T) in obs.dynamicType.observe(obs) }
But this line of code drives my XCode crazy with some Segmentation Fault: 11 on compilation (and Communication interrupted with Playground ..)
Is there any workaround for what I'm trying to do ?

I haven't tested but you can try:
#objc protocol Observer : NSObjectProtocol {
func observe(param: String) -> Void
}
func addObserver<T: AnyObject where T: Observer>(observer: T) {
let f: T -> String -> Void = { ($0 as AnyObject).observe }
entries.addObserver(observer, f)
}
At least, this compiles because AnyObject has all methods from ObjC - including #objc - classes/protocols, as ImplicitlyUnwrappedOptional.
So, this compiles:
let str = NSString(string: "test")
(str as AnyObject).observe("foo")
Of course this causes runtime error because NSString has no observe(_:) method. But, in your case, T is guaranteed to be Observer, it should works.

Related

Overloading generic functions in iOS Swift

I am trying to build a finder that tries and finds multiple types that are being passed to it inside a closure.
enum SomeError: Error {
case notInitialized
}
struct TestFinder {
func getSomething<T, U>(_ function: #escaping (T) -> U) throws -> U {
guard let t: T = get() else {
throw SomeError.notInitialized
}
return function(t)
}
func getSomething<T, U, V>(_ function: #escaping (T, U) -> V) throws -> V {
guard let t: T = get(), let u: U = get() else {
throw SomeError.notInitialized
}
return function(t, u)
}
func getSomething<T, U, V, W>(_ function: #escaping (T, U, V) -> W) throws -> W {
guard let t: T = get(), let u: U = get(), let v: V = get() else {
throw SomeError.notInitialized
}
return function(t, u, v)
}
private func get<T>() -> T? {
nil
}
}
struct UserDetails {
let name: String
let roll: String
}
I call the finder as:
let testReturnType = try? TestFinder().getSomething(UserDetails.init)
Compiler throws me an error of:
Ambiguous use of 'getSomething'
Reason for this error (from docs):
You can overload a generic function or initializer by providing different constraints, requirements, or both on the type parameters. When you call an overloaded generic function or initializer, the compiler uses these constraints to resolve which overloaded function or initializer to invoke.
But if I comment:
func getSomething<T, U>(_ function: #escaping (T) -> U) throws -> U
Everything starts working. It has something to do with the compiler not able to identify which function signature to resolve.
Any particular solution for this?
You haven't quite focussed on the actual issue. Let's eliminate everything irrelevant from the example. This compiles and works as expected:
struct TestFinder {
func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
print("two")
}
func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
print("three")
}
func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
print("four")
}
}
And here we'll test it:
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f) // "four"
But if you add the version with one passed function parameter, everything breaks down:
struct TestFinder {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
}
func doSomething<T,U>(_ function: (T,U) -> Void) -> Void {
print("two")
}
func doSomething<T,U,V>(_ function: (T,U,V) -> Void) -> Void {
print("three")
}
func doSomething<T,U,V,W>(_ function: (T,U,V,W) -> Void) -> Void {
print("four")
}
}
Now we can't compile, because the first version is seen as a candidate. And indeed, if we remove the other versions, we still compile!
struct TestFinder {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
}
}
That's the weird part. We still compile, even though we are saying:
func f(_ s1: String, _ s2: String, _ s3: String, _ s4: String) -> Void {}
TestFinder().doSomething(f)
Evidently, this function with four parameters is seen by the compiler as "fitting" the declaration with just one generic parameter.
I regard this as a bug. I think I can guess what might cause it; it could have to do with the legacy of function parameter list as tuples. This function f is "equivalent" to a function taking a single parameter consisting of a four-string tuple. Nevertheless, you cannot actually call the function inside doSomething with a four-string tuple; I cannot find a way to call it at all.
So, I would say, regard this as a bug, and work around it for now by removing the first version of your generic.
UPDATE: On the advice of the Swift team, I tested with the May 4, 2020 Swift 5.3 Development toolchain. With it, your code compiles and behaves as expected. This was indeed a bug, and it was fixed as part of
https://bugs.swift.org/browse/SR-8563
Returning for a moment to my version, my code, too, compiles and behaves as expected, with all four versions of doSomething present. However, note that if you delete all but the first version of doSomething, it still compiles and runs. Moreover, you can call function with four parameters by bundling them into a tuple and force casting, like this:
struct TestFinder2 {
func doSomething<T>(_ function: (T) -> Void) -> Void {
print("one")
function(("manny", "moe", "jack", "henry") as! T)
}
}
That seems to confirm my guess that what you're seeing is a consequence of the hidden tuple-nature of a function's parameter list. One can draw the same conclusion from the discussion of the bug, which refers to "tuple-splatting".
The key point is the UserDetails struct, because this struct has two properties and without any designed initializer, the initializer could be UserDetails(name: , roll: ) or UserDetails(name: ) or UserDetails(roll: ), this is the ambitious part. if you just delete one property of UserDetails that will work too, because one property struct has only one designed initializer.
If you comment
func getSomething<T, U>(_ function: #escaping (T) -> U) throws -> U
Which means the finder has only one chosen:
func getSomething<T,U,V>(_ function: #escaping(T,U) -> V) throws -> V

Use Generic Protocol as Interface

I want to create a UseCase protocol, using generic protocol. Then I want to create an interface for all implementation, in order to create mocks for tests.
Here is what I have done so far:
struct Product {}
protocol UseCase {
associatedtype ReturnType
associatedtype Param
func execute(_ params: Param, completion: ((ReturnType) -> Void))
}
protocol FetchProductsUseCase: UseCase {
associatedtype ReturnType = [Product]
associatedtype Param = Void
}
struct FetchProductsUseCaseImpl: FetchProductsUseCase {
func execute(_ params: Param , completion: ((ReturnType) -> Void)) {
completion([])
}
}
//ERROR: Protocol 'FetchProductsUseCase' can only be used as a generic constraint because it has Self or associated type requirements
var useCase: FetchProductsUseCase!
Can someone help me to fix that?
I've search over SOF, and I found multiple of topics about generics, but none of them are helpful for my case.
So there is no way to "constraint" the FetchProductUse case to only accept one couple of Generics ? ( ie: Void/[Product] ) ?
Yes, but your FetchProductsUseCase is not how you do it. Do this instead:
struct AnyUseCase<P, R>: UseCase {
typealias ReturnType = R
typealias Param = P
init<U>(useCase: U) where U: UseCase, U.ReturnType == ReturnType, U.Param == Param {
_execute = useCase.execute
}
func execute(_ params: P, completion: ((R) -> Void)) {
_execute(params, completion)
}
let _execute: (P, (R) -> Void) -> Void
}
var useCase: AnyUseCase<Void, [Product]>!
Then you can do something like:
useCase = AnyUseCase(useCase: FetchProductsUseCaseImpl())
I think your next error is going to be that completion is not escaping. It probably needs to be.

Swift: Specializing method implementation with protocol extensions

To provide some context:
P stands for property. The purpose of the code is that values of different types should be handled by individual methods (e.g. serializeInt, serializeDouble etc.), something like method overloading but the type of the argument coming from a type parameter.
The code below actually works fine. It calls the specialized pr( _: Int) implementation and prints "int".
But if I change the declaration "func pr(_ t: Int)" to the commented out one "func pr(_ t: T)", then the generic version gets called.
Anyone has any pointers to where this behavior is specified or why it works like this?
protocol P {
associatedtype T
// this will be 'specialized' for concrete types
func pr(_ t: T)
// the operation that should call different pr implementations depending on T
func op(_ t: T)
}
extension P {
func op(_ t: T) {
pr(t)
}
}
// fallback implementation
extension P {
func pr(_ t: T) {
print("generic")
}
}
// pr 'specialized' on Int
extension P where T == Int {
// func pr(_ t: T) {
func pr(_ t: Int) {
print("int")
}
}
struct Prop<T>: P {
}
// create an Int prop and do the op
let p = Prop<Int>()
p.op(1)
Don't see any weird behavior. If you uncomment this line – func pr(_ t: T) {
Here p.op(1) will call default method, because you haven't provided implementation for op method where T == Int. And default op call default pr that's why it prints "generic".

Declaration 'subscribe' cannot override more than one superclass declaration (ReSwift)

I'm having a problem when overriding a function from the ReSwift Pod. I've got the following mock class:
import Foundation
import Quick
import Nimble
import RxSwift
#testable import MainProject
#testable import ReSwift
class MockReSwiftStore: ReSwift.Store<MainState> {
var dispatchDidRun: Bool = false
var subscribeWasTriggered: Bool = false
init() {
let reducer: Reducer<MainState> = {_, _ in MainState() }
super.init(reducer: reducer, state: nil)
}
required init(
reducer: #escaping (Action, State?) -> State,
state: State?,
middleware: [(#escaping DispatchFunction, #escaping () -> State?) -> (#escaping DispatchFunction) -> DispatchFunction]) {
super.init(reducer: reducer, state: state, middleware: middleware)
}
override func subscribe<SelectedState, S>(
_ subscriber: S,
transform: ((Subscription<MainState>) -> Subscription<SelectedState>)?)
where S: StoreSubscriber,
S.StoreSubscriberStateType == SelectedState {
subscribeWasTriggered = true
}
}
}
And when overriding the subscribe method I'm getting following errors
Then when using autocomplete it also shows 2 occurences:
However when looking for the original function there's only one which looks like this
open func subscribe<SelectedState, S: StoreSubscriber>(
_ subscriber: S, transform: ((Subscription<State>) -> Subscription<SelectedState>)?
) where S.StoreSubscriberStateType == SelectedState
{
// Create a subscription for the new subscriber.
let originalSubscription = Subscription<State>()
// Call the optional transformation closure. This allows callers to modify
// the subscription, e.g. in order to subselect parts of the store's state.
let transformedSubscription = transform?(originalSubscription)
_subscribe(subscriber, originalSubscription: originalSubscription,
transformedSubscription: transformedSubscription)
}
This is my compiler output
I'm out of ideas so any help is greatly appreciated
Thanks!
Here is your issue:
class Some<T> {
func echo() {
print("A")
}
}
extension Some where T: Equatable {
func echo() {
print("B")
}
}
class AnotherSome: Some<String> {
override func echo() {
print("Doesn't compile")
}
}
The problem is: ReSwift developers declare Store.subscribe behavior as a part of interface and as a part of extension (I am not sure why they chose to do it instead of introducing other objects). Swift can't figure out which part you are trying to override and thus it doesn't compile. Afaik there are no language instruments which allow you to resolve this issue.
A possible solution is to implement MockStore as a StoreType and use Store object to implement behavior for StoreType interface.

In Swift protocols - Why am I being forced to use the keyword 'Final' before my Sheep class? [duplicate]

I have a protocol P that returns a copy of the object:
protocol P {
func copy() -> Self
}
and a class C that implements P:
class C : P {
func copy() -> Self {
return C()
}
}
However, whether I put the return value as Self I get the following error:
Cannot convert return expression of type 'C' to return type 'Self'
I also tried returning C.
class C : P {
func copy() -> C {
return C()
}
}
That resulted in the following error:
Method 'copy()' in non-final class 'C' must return Self to conform
to protocol 'P'
Nothing works except for the case where I prefix class C with final ie do:
final class C : P {
func copy() -> C {
return C()
}
}
However if I want to subclass C then nothing would work. Is there any way around this?
The problem is that you're making a promise that the compiler can't prove you'll keep.
So you created this promise: Calling copy() will return its own type, fully initialized.
But then you implemented copy() this way:
func copy() -> Self {
return C()
}
Now I'm a subclass that doesn't override copy(). And I return a C, not a fully-initialized Self (which I promised). So that's no good. How about:
func copy() -> Self {
return Self()
}
Well, that won't compile, but even if it did, it'd be no good. The subclass may have no trivial constructor, so D() might not even be legal. (Though see below.)
OK, well how about:
func copy() -> C {
return C()
}
Yes, but that doesn't return Self. It returns C. You're still not keeping your promise.
"But ObjC can do it!" Well, sort of. Mostly because it doesn't care if you keep your promise the way Swift does. If you fail to implement copyWithZone: in the subclass, you may fail to fully initialize your object. The compiler won't even warn you that you've done that.
"But most everything in ObjC can be translated to Swift, and ObjC has NSCopying." Yes it does, and here's how it's defined:
func copy() -> AnyObject!
So you can do the same (there's no reason for the ! here):
protocol Copyable {
func copy() -> AnyObject
}
That says "I'm not promising anything about what you get back." You could also say:
protocol Copyable {
func copy() -> Copyable
}
That's a promise you can make.
But we can think about C++ for a little while and remember that there's a promise we can make. We can promise that we and all our subclasses will implement specific kinds of initializers, and Swift will enforce that (and so can prove we're telling the truth):
protocol Copyable {
init(copy: Self)
}
class C : Copyable {
required init(copy: C) {
// Perform your copying here.
}
}
And that is how you should perform copies.
We can take this one step further, but it uses dynamicType, and I haven't tested it extensively to make sure that is always what we want, but it should be correct:
protocol Copyable {
func copy() -> Self
init(copy: Self)
}
class C : Copyable {
func copy() -> Self {
return self.dynamicType(copy: self)
}
required init(copy: C) {
// Perform your copying here.
}
}
Here we promise that there is an initializer that performs copies for us, and then we can at runtime determine which one to call, giving us the method syntax you were looking for.
With Swift 2, we can use protocol extensions for this.
protocol Copyable {
init(copy:Self)
}
extension Copyable {
func copy() -> Self {
return Self.init(copy: self)
}
}
There is another way to do what you want that involves taking advantage of Swift's associated type. Here's a simple example:
public protocol Creatable {
associatedtype ObjectType = Self
static func create() -> ObjectType
}
class MyClass {
// Your class stuff here
}
extension MyClass: Creatable {
// Define the protocol function to return class type
static func create() -> MyClass {
// Create an instance of your class however you want
return MyClass()
}
}
let obj = MyClass.create()
Actually, there is a trick that allows to easily return Self when required by a protocol (gist):
/// Cast the argument to the infered function return type.
func autocast<T>(some: Any) -> T? {
return some as? T
}
protocol Foo {
static func foo() -> Self
}
class Vehicle: Foo {
class func foo() -> Self {
return autocast(Vehicle())!
}
}
class Tractor: Vehicle {
override class func foo() -> Self {
return autocast(Tractor())!
}
}
func typeName(some: Any) -> String {
return (some is Any.Type) ? "\(some)" : "\(some.dynamicType)"
}
let vehicle = Vehicle.foo()
let tractor = Tractor.foo()
print(typeName(vehicle)) // Vehicle
print(typeName(tractor)) // Tractor
Swift 5.1 now allow a forced cast to Self, as! Self
1> protocol P {
2. func id() -> Self
3. }
9> class D : P {
10. func id() -> Self {
11. return D()
12. }
13. }
error: repl.swift:11:16: error: cannot convert return expression of type 'D' to return type 'Self'
return D()
^~~
as! Self
9> class D : P {
10. func id() -> Self {
11. return D() as! Self
12. }
13. } //works
Following on Rob's suggestion, this could be made more generic with associated types. I've changed the example a bit to demonstrate the benefits of the approach.
protocol Copyable: NSCopying {
associatedtype Prototype
init(copy: Prototype)
init(deepCopy: Prototype)
}
class C : Copyable {
typealias Prototype = C // <-- requires adding this line to classes
required init(copy: Prototype) {
// Perform your copying here.
}
required init(deepCopy: Prototype) {
// Perform your deep copying here.
}
#objc func copyWithZone(zone: NSZone) -> AnyObject {
return Prototype(copy: self)
}
}
I had a similar problem and came up with something that may be useful so I though i'd share it for future reference because this is one of the first places I found when searching for a solution.
As stated above, the problem is the ambiguity of the return type for the copy() function. This can be illustrated very clearly by separating the copy() -> C and copy() -> P functions:
So, assuming you define the protocol and class as follows:
protocol P
{
func copy() -> P
}
class C:P
{
func doCopy() -> C { return C() }
func copy() -> C { return doCopy() }
func copy() -> P { return doCopy() }
}
This compiles and produces the expected results when the type of the return value is explicit. Any time the compiler has to decide what the return type should be (on its own), it will find the situation ambiguous and fail for all concrete classes that implement the P protocol.
For example:
var aC:C = C() // aC is of type C
var aP:P = aC // aP is of type P (contains an instance of C)
var bC:C // this to test assignment to a C type variable
var bP:P // " " " P " "
bC = aC.copy() // OK copy()->C is used
bP = aC.copy() // Ambiguous.
// compiler could use either functions
bP = (aC as P).copy() // but this resolves the ambiguity.
bC = aP.copy() // Fails, obvious type incompatibility
bP = aP.copy() // OK copy()->P is used
In conclusion, this would work in situations where you're either, not using the base class's copy() function or you always have explicit type context.
I found that using the same function name as the concrete class made for unwieldy code everywhere, so I ended up using a different name for the protocol's copy() function.
The end result is more like:
protocol P
{
func copyAsP() -> P
}
class C:P
{
func copy() -> C
{
// there usually is a lot more code around here...
return C()
}
func copyAsP() -> P { return copy() }
}
Of course my context and functions are completely different but in spirit of the question, I tried to stay as close to the example given as possible.
Just throwing my hat into the ring here. We needed a protocol that returned an optional of the type the protocol was applied on. We also wanted the override to explicitly return the type, not just Self.
The trick is rather than using 'Self' as the return type, you instead define an associated type which you set equal to Self, then use that associated type.
Here's the old way, using Self...
protocol Mappable{
static func map() -> Self?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> Self? {
...
}
}
Here's the new way using the associated type. Note the return type is explicit now, not 'Self'.
protocol Mappable{
associatedtype ExplicitSelf = Self
static func map() -> ExplicitSelf?
}
// Generated from Fix-it
extension SomeSpecificClass : Mappable{
static func map() -> SomeSpecificClass? {
...
}
}
To add to the answers with the associatedtype way, I suggest to move the creating of the instance to a default implementation of the protocol extension. In that way the conforming classes won't have to implement it, thus sparing us from code duplication:
protocol Initializable {
init()
}
protocol Creatable: Initializable {
associatedtype Object: Initializable = Self
static func newInstance() -> Object
}
extension Creatable {
static func newInstance() -> Object {
return Object()
}
}
class MyClass: Creatable {
required init() {}
}
class MyOtherClass: Creatable {
required init() {}
}
// Any class (struct, etc.) conforming to Creatable
// can create new instances without having to implement newInstance()
let instance1 = MyClass.newInstance()
let instance2 = MyOtherClass.newInstance()

Resources