Swift compiler is unable to resolve recursive use of generics - swift

I am trying to implement the chain of responsibility pattern in Swift.
public class Chain<T, U> {
private var command: (T?, (U?) -> Void) -> Void
private var runCommand: (() -> Void)?
private var nextCommand: ((U?) -> Void)?
private init(command: (T?, (U?) -> Void) -> Void) {
self.command = command
}
private func next(u: U?) {
self.nextCommand?(u)
}
func then<V>(command: (U?, (V?) -> Void) -> Void) -> Chain<U, V> {
let c = Chain<U, V>(command: command)
self.nextCommand = { command($0, c.next) }
c.runCommand = self.runCommand
return c
}
func endWith(command: (U?) -> Void) {
self.nextCommand = command
self.runCommand!()
}
static func build<V>(command: ((V?) -> Void) -> Void) -> Chain<AnyObject, V> {
let c = Chain<AnyObject, V>(command: { _, next in command(next) })
c.runCommand = { command(c.next) }
return c
}
}
My class does not raise any compilation error but a simple use case (such as the one below) does not work. It raises the following error: error: cannot invoke 'endWith' with an argument list of type '((_?) -> ()) ; expected an argument list of type '((U?) -> Void)'
Any thought?
Chain.build { next in
print("Foo")
next("Bar")
}
.then { o, next in
print(o)
next(15)
}
.endWith { o in
print(o)
}
I know it is an edge case of generics usage in Swift. However, as it is not possible to explicitly specialize a generic type, I have not found any solution so far.

The compiler isn't able to infer the types in your example. You just need to specify them where they're ambiguous:
Chain<String,Int>.build { next in
print("Foo")
next("Bar")
}
.then { (o: String?, next: Int? -> Void) in
print(o)
next(15)
}
.endWith { o in
print(o)
}

Related

How do I write the not/negate higher order function in swift?

I am a Javascripter and I love using the not/negate function:
function not (predicateFunc) {
return function () {
return !predicateFunc.apply(this, arguments);
};
}
I am trying to do the same thing with swift:
func not <A> (_ f: #escaping (_ A: Any) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But I am getting errors like
generic parameter 'T' could not be inferred
and
Cannot convert value of type '(_) -> Bool' to expected argument type '(Any) -> Bool'
The outcome I am looking for is when I have a function like this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
I can just create a notEmpty function like this:
let notEmpty = not(isEmpty)
And then use it like
notEmpty([3,4,5]) // true
What am I doing wrong?
Using Any is a code smell. You can just extend Collection directly:
extension Collection {
var notEmpty: Bool {
return !isEmpty
}
}
[1, 3, 5].notEmpty // true
Your functional definition of not can work like this:
func not <A> (_ f: #escaping (_ a: A) -> Bool) -> (A) -> Bool {
return { a in !f(a) }
}
But to call it you would need something like this:
let arrayNotEmpty = not { (array: [Int]) in array.isEmpty }
arrayNotEmpty([1, 3, 5]) // true
You have two errors:
You're using A as both the type parameter and as the argument name.
You're using Any as the argument type instead of using the type parameter (A) as the argument type.
Try this:
func not<A>(predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
Note that in this version, I'm not using argument names for the predicate argument. You don't need an argument name in the declaration ((A) -> Bool) and I'm using the anonymous argument name ($0) in the body.
Okay, so you want to write this:
func isEmpty<T: Collection>(collection: T) -> Bool {
return collection.count == 0
}
func not<A>(_ predicate: #escaping (A) -> Bool) -> (A) -> Bool {
return { !predicate($0) }
}
let notEmpty = not(isEmpty)
And you get this error:
let notEmpty = not(isEmpty)
^ Generic parameter 'A' could not be inferred
The problem is that this code tries to create a generic closure, but Swift doesn't support generic closures.
That is to say, what would the type of nonEmpty be? It would be something like:
<A: Collection>(A) -> Bool
and Swift doesn't support that.

Swift 4 extension function on generic protocol which takes a generic function as parameter

swift --version
Swift version 4.1 (swift-4.1-RELEASE)
Target: x86_64-unknown-linux-gnu
Given a simple protocol which defines a generic producer (Source):
protocol Source {
associatedtype T
func produce() -> T
}
And a mapping capable of converting between source types:
struct Mapping<T, U : Source> : Source {
typealias Transformation = (U.T) -> T
private let upstream : U
private let block : Transformation
init(_ upstream: U, _ block : #escaping Transformation) {
self.upstream = upstream
self.block = block
}
func produce() -> T {
return block(upstream.produce())
}
}
And a sample source which produces static text:
struct TextSource : Source {
private let text : String
init(_ text: String) {
self.text = text
}
func produce() -> String {
return text
}
}
I can use this to, e.g., count characters...
let t = TextSource("Hi!")
let f = Mapping(t, { (text: String) -> Int in
return text.count
})
print(f.produce()) // output: 3
But I'd rather like to use a generic map extension function on Source such that transformations can be chained, e.g.:
let t = TextSource("Hi!").map { (text: String) -> Int in
return text.count
}
Approach A
extension Source {
func map<T, U : Source>(_ block: #escaping Mapping<T, U>.Transformation) -> Source {
return Mapping(self, block)
}
}
That is rejected by the swift compiler:
error: generic parameter 'U' is not used in function signature
func map<T, U : Source>(_ block: #escaping Mapping<T, U>.Transformation) -> Source {
^
Approach B
extension Source {
func map<T>(_ block: #escaping Mapping<T, U>.Transformation) -> Source {
return Mapping(self, block)
}
}
In this case the compiler complains about the missing type parameter:
error: use of undeclared type 'U'
func map<T>(_ block: #escaping Mapping<T, U>.Transformation) -> Source {
^
Question
Which type parameters and constraints need to be specified on the map extension function in order to satisfy the compiler?
You cannot use Source as a concrete return type for map because it is a protocol with an associated type requirement.
To solve this, you can have the map function return Mapping<X, Self>:
extension Source {
func map<Result>(_ transform: #escaping (T) -> Result) -> Mapping<Result, Self> {
return Mapping(self, transform)
}
}
The function now has a Self requirement. The resulting Mapping type has a generic type parameter Self that is replaced by the concrete implementation of Source, e.g. Mapping or TextSource.

Cannot convert value of type '(T) -> Void'

Example:
struct Wrapper<T> {
var key: Int = 0
var listeners: [Int: (T) -> Void] = Dictionary()
mutating func add(_ handler:#escaping (T) -> Void) {
self.key += 1
self.listeners[self.key] = handler
}
func get(key: Int) -> (T) -> Void {
return self.listeners[key]!
}
}
Test protocol:
protocol CommonProtocol {
}
Class that create Wrapper of test class
class C {
var wrapper: Wrapper = Wrapper<CommonProtocol>()
func add<T: CommonProtocol>(_ handler: #escaping (T) -> Void) {
self.wrapper.add(handler) //Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'
}
}
Image with error
I get error:
Cannot convert value of type '(T) -> Void' to expected argument type '(CommonProtocol) -> Void'
Question:
Why (T) -> Void can't be casted to (CommonProtocol) -> Void ? The T
is explicitly declared as <T: CommonProtocol>
This is my first question, if you have some suggestions please don't hesitate to contact me
You don't need to make func add generic.
When you specify in func add<T: CommonProtocol>... you explicitly telling the compiler that your function accepts all Types that inherit CommonProtocol but your Wrapper specifies that accepts CommonProtocol not inherited types.
Solution
Either type-erase class C:
Class C<T: CommonProtocol> {
var wrapper: Wrapper<T>
....
}
or if type T doesn't actually matter to you then:
func add(_ handler: #escaping (CommonProtocol) -> Void)
but second one doesn't make sense at all. You have to downcast it every-time you'll use this method (and downcasts are very bad :D)
Note: It's actually not related to this question, but one of your options is to type-erase the CommonProtocol too.

Generic protocol functions & lvalue in swift

I am encountering the following error when I try to call a stored closure. I get this error when I try to build:
'(T) -> Void' is not convertible to '#lvalue (T) -> Void' (aka '#lvalue (T) -> ()')
public protocol DataSourceProtocol {
associatedtype DataSourceItem
func item(indexPath: IndexPath) -> DataSourceItem?
func update<T>(sender : T)
}
public class AnyDataSourceSimple<T> : DataSourceProtocol {
private var itemClosure : (IndexPath) -> T?
private var updateClosure: (T) -> Void
public init<I: DataSourceProtocol>(_ concrete: I) where I.DataSourceItem == T {
self.itemClosure = concrete.item
self.updateClosure = concrete.update
}
public func item(indexPath: IndexPath) -> T? {
return itemClosure(indexPath)
}
public func update<T>(sender: T) {
// '(T) -> Void' is not convertible to '#lvalue (T) -> Void' (aka '#lvalue (T) -> ()')
updateClosure(sender)
print("update")
}
}
Is this somehow related to a generic function definition within a protocol?
As in the comments, your T for generic function is separate for the T in the definition of the generic class.
To make it compile you have to do it like this, not sure if this is what you meant
import Foundation
public protocol DataSourceProtocol {
associatedtype DataSourceItem
associatedtype UpdateSender
func item(indexPath: IndexPath) -> DataSourceItem?
func update(sender : UpdateSender)
}
public class AnyDataSourceSimple<T> : DataSourceProtocol {
private var itemClosure : (IndexPath) -> T?
private var updateClosure: (T) -> Void
public init<I: DataSourceProtocol>(_ concrete: I) where I.DataSourceItem == T, I.UpdateSender == T {
self.itemClosure = concrete.item
self.updateClosure = concrete.update
}
public func item(indexPath: IndexPath) -> T? {
return itemClosure(indexPath)
}
public func update(sender: T) {
updateClosure(sender)
print("update")
}
}

Swift override static method compile error

I have these two swift classes:
class A {
static func list(completion: (_ result:[A]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
static func list(completion: (_ result:[B]?) -> Void) {
completion (nil)
}
static func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
Trying to compile this raise the error "overriding declaration requires an 'override' keyword" but just for the 'get' method of class B. 'list' method compiles fine. What is the difference between [B]? and B? for the compiler in this case?
Edit: Also notice that adding 'override' is not possible. I get the error 'Cannot override static method'.
In class B, the method list is a separate method from list in class A. They just share the same name, that's all.
The parameters of the two list methods are actually different:
// A.list
static func list(completion: (_ result:[A]?) -> Void) {
// B.list
static func list(completion: (_ result:[B]?) -> Void) {
A.list takes an argument of type (_ result: [A]?) -> Void while B.list takes a (_ result: [B]?) -> Void. The array type in the closure type's parameter list is different!
So you're not overridding anything, you're just overloading.
Note:
static methods can never be overridden! If you want to override a method, use class instead of static.
class A {
class func get(completion: (_ result:A?) -> Void) {
completion (nil)
}
}
class B: A {
override class func get(completion: (_ result:B?) -> Void) {
completion (nil)
}
}
In short, as per rule, static methods can't be overridden.