Why infix operator (bind) fails when it is declared outside of main file? - swift

In my Xcode project, I have a main.swift file, with this contents:
func main() -> Void {
return print(
half(80) >>= half >>= half
)
}
func half(_ a: Int) -> Int? {
return a % 2 == 0 ? Optional(a / 2) : Optional.none
}
main()
In another file, let's call it test.swift, I have:
precedencegroup BindPrecedence {
associativity: left
higherThan: NilCoalescingPrecedence
}
infix operator >>= : BindPrecedence
func >>= <T, U>(_ a: T?, _ k: (T) -> U?) -> U? {
return a.flatMap(k)
}
When I execute main, the following errors display:
- Generic parameter 'U' could not be inferred
- Cannot convert value of type '()' to expected argument type '(Int) -> U?'
- Left side of mutating operator isn't mutable: 'half' is a function
- Type '(Int) -> Int?' cannot conform to 'BinaryInteger'; only struct/enum/class types can conform to protocols
- Required by referencing operator function '>>=' on 'BinaryInteger' where 'Self' = '(Int) -> Int?'
However, if I put the contents of test.swift file below my main function inside main.swift, the errors disappear.
Is there any specific rule concerning the declaration of infix operators and precedence groups ? Do I have to put everything inside main.swift to make it work ?
I will appreciate any insights into this issue.

So the issue is half >>= half which is actually trying to match (Int) -> Int? >>= (Int) -> Int? which doesn't have an operator for that.
So in my testing I solved it with these changes:
precedencegroup BindPrecedence {
associativity: right // This changed
higherThan: NilCoalescingPrecedence
}
infix operator >>= : BindPrecedence
func >>= <T, U>(_ a: T?, _ k: (T) -> U?) -> U? {
return a.flatMap(k)
}
func >>= <T, U, V> (_ k1: #escaping (T) -> U?, _ k2: #escaping (U) -> V?) -> (T) -> V? {
{ k1($0).flatMap(k2) }
}
I imagine you could get it working with a associativity: left like you had it but this has the advantage of short circuiting as soon as one operation gives you nil.
Edit:
I'll also add it should work how you have it but type checking is hard. You could likely file this as a bug against the compiler.

Related

Why does Swift not allow a type conforming to a protocol to be used in an argument taking the protocol?

Given this example code:
private protocol P {}
final private class X {
private func j(j: (P) -> Void) -> Void {}
private func jj<Z: P>(jj: (Z) -> Void) -> Void {
j(j: jj)
}
}
Swift 4 in XCode 9.1 gives this compiler error on the line j(j: jj):
Cannot convert value of type ‘(Z) -> Void’ to expected argument type
‘(P) -> Void’.
Why?
Note, it seems to me that it should not give this error, because the type constraint <Z: P> requires that Z absolutely must conform to protocol P. So, there should be absolutely no reason to convert from Z to P, since Z already conforms to P.
Seems like a compiler bug to me...
The compiler is correct – a (Z) -> Void is not a (P) -> Void. To illustrate why this is the case, let's define the following conformances:
extension String : P {}
extension Int : P {}
Now let's substitute Int for Z:
final private class X {
func j(j: (P) -> Void) {
j("foob")
}
func jj(jj: (Int) -> Void) {
// error: Cannot convert value of type '(Int) -> Void' to expected argument
// type '(P) -> Void'
j(j: jj)
}
}
We cannot pass an (Int) -> Void to a (P) -> Void. Why? Well a (P) -> Void accepts anything that conforms to P – for example, we could pass in a String. But the function that we're passing to j is actually an (Int) -> Void, so we're trying to pass a String to an Int parameter, which is clearly unsound.
If we put the generics back in, it should still be fairly clear why this cannot work:
final private class X {
func j(j: (P) -> Void) {
j("foob")
}
func jj<Z : P>(jj: (Z) -> Void) {
// error: Cannot convert value of type '(Z) -> Void' to expected argument
// type '(P) -> Void'
j(j: jj)
}
}
X().jj { (i: Int) in
print(i) // What are we printing here? A String gets passed in the above implementation..
}
(P) -> Void is a function can deal with any P conforming argument. However (Z) -> Void is a function that can only deal with one specific concrete typed argument that conforms to P (e.g Int in our above example). Typing it as a function that can deal with any P conforming argument would be a lie.
Put in more technical manner, (Z) -> Void is not a subtype of (P) -> Void. Functions are contravariant with respect to their parameter types, meaning that (U) -> Void is a subtype of (V) -> Void if and only if V is a subtype of U. But P is not a subtype of Z : P – Z is a placeholder that is replaced at runtime with a concrete type that conforms to (so is a subtype of) P.
The more interesting part comes when we consider the opposite; that is, passing a (P) -> Void to a (Z) -> Void. Although the placeholder Z : P can only be satisfied by a concrete subtype of P, we cannot substitute P for Z because protocols don't conform to themselves.

Swift Generics: Cannot convert value of type to expected argument type

Here is my code:
protocol SomeProtocol {
}
class A: SomeProtocol {
}
func f1<T: SomeProtocol>(ofType: T.Type, listener: (T?) -> Void) {
}
func f2<T: SomeProtocol>(ofType: T.Type, listener: ([T]?) -> Void) {
}
func g() {
let l1: (SomeProtocol?) -> Void = ...
let l2: ([SomeProtocol]?) -> Void = ...
f1(ofType: A.self, listener: l1) // NO ERROR
f2(ofType: A.self, listener: l2) // COMPILE ERROR: Cannot convert value of type '([SomeProtocol]?) -> Void' to expected argument type '([_]?) -> Void'
}
What is the problem with the second closure having an argument of an array of generic type objects?
Swift 4.1 Update
This is a bug that was fixed in this pull request, which will make it into the release of Swift 4.1. Your code now compiles as expected in a 4.1 snapshot.
Pre Swift 4.1
This just looks like you're just stretching the compiler too far.
It can deal with conversions from arrays of sub-typed elements to arrays of super-typed elements, e.g [A] to [SomeProtocol] – this is covariance. It's worth noting that arrays have always been an edge case here, as arbitrary generics are invariant. Certain collections, such as Array, just get special treatment from the compiler allowing for covariance.
It can deal with conversions of functions with super-typed parameters to functions with sub-typed parameters, e.g (SomeProtocol) -> Void to (A) -> Void – this is contravariance.
However it appears that it currently cannot do both in one go (but really it should be able to; feel free to file a bug).
For what it's worth, this has nothing to do with generics, the following reproduces the same behaviour:
protocol SomeProtocol {}
class A : SomeProtocol {}
func f1(listener: (A) -> Void) {}
func f2(listener: ([A]) -> Void) {}
func f3(listener: () -> [SomeProtocol]) {}
func g() {
let l1: (SomeProtocol) -> Void = { _ in }
f1(listener: l1) // NO ERROR
let l2: ([SomeProtocol]) -> Void = { _ in }
f2(listener: l2)
// COMPILER ERROR: Cannot convert value of type '([SomeProtocol]) -> Void' to
// expected argument type '([A]) -> Void'
// it's the same story for function return types
let l3: () -> [A] = { [] }
f3(listener: l3)
// COMPILER ERROR: Cannot convert value of type '() -> [A]' to
// expected argument type '() -> [SomeProtocol]'
}
Until fixed, one solution in this case is to simply use a closure expression to act as a trampoline between the two function types:
// converting a ([SomeProtocol]) -> Void to a ([A]) -> Void.
// compiler infers closure expression to be of type ([A]) -> Void, and in the
// implementation, $0 gets implicitly converted from [A] to [SomeProtocol].
f2(listener: { l2($0) })
// converting a () -> [A] to a () -> [SomeProtocol].
// compiler infers closure expression to be of type () -> [SomeProtocol], and in the
// implementation, the result of l3 gets implicitly converted from [A] to [SomeProtocol]
f3(listener: { l3() })
And, applied to your code:
f2(ofType: A.self, listener: { l2($0) })
This works because the compiler infers the closure expression to be of type ([T]?) -> Void, which can be passed to f2. In the implementation of the closure, the compiler then performs an implicit conversion of $0 from [T]? to [SomeProtocol]?.
And, as Dominik is hinting at, this trampoline could also be done as an additional overload of f2:
func f2<T : SomeProtocol>(ofType type: T.Type, listener: ([SomeProtocol]?) -> Void) {
// pass a closure expression of type ([T]?) -> Void to the original f2, we then
// deal with the conversion from [T]? to [SomeProtocol]? in the closure.
// (and by "we", I mean the compiler, implicitly)
f2(ofType: type, listener: { (arr: [T]?) in listener(arr) })
}
Allowing you to once again call it as f2(ofType: A.self, listener: l2).
The listener closure in func f2<T: SomeProtocol>(ofType: T.Type, listener: ([T]?) -> Void) {...} requires its argument to be an array of T, where T is a type that implements SomeProtocol. By writing <T: SomeProtocol>, you are enforcing that all elements of that array are of the same type.
Say for example you have two classes: A and B. Both are completely distinct. Yet both implement SomeProtocol. In this case, the input array cannot be [A(), B()] because of the type constraint. The input array can either be [A(), A()] or [B(), B()].
But, when you define l2 as let l2: ([SomeProtocol]?) -> Void = ..., you allow the closure to accept an argument such as [A(), B()]. Hence this closure, and the closure you define in f2 are incompatible and the compiler cannot convert between the two.
Unfortunately, you cannot add type enforcement to a variable such as l2 as stated here. What you can do is if you know that l2 is going to work on arrays of class A, you could redefine it as follows:
let l2: ([A]?) -> Void = { ... }
Let me try and explain this with a simpler example. Let's say you write a generic function to find the greatest element in an array of comparables:
func greatest<T: Comparable>(array: [T]) -> T {
// return greatest element in the array
}
Now if you try calling that function like so:
let comparables: [Comparable] = [1, "hello"]
print(greatest(array: comparables))
The compiler will complain since there is no way to compare an Int and a String. What you must instead do is follows:
let comparables: [Int] = [1, 5, 2]
print(greatest(array: comparables))
Have nothing on Hamish's answer, he is 100% right. But if you wanna super simple solution without any explanation or code just work, when working with array of generics protocol, use this:
func f1<T: SomeProtocol>(ofType: T.Type, listener: (T?) -> Void) {
}
func f2<Z: SomeProtocol>(ofType: Z.Type, listener: ([SomeProtocol]?) -> Void) {
}

How to fix : "passing non-escaping parameter to function expecting #escaping closure"

I'm experimenting usage of closurse for First Order Predicate calculus, and
I intend to define the following function :
func ASSUM<U, V>(p: #escaping Pred<U>) -> (Pred<U>) -> Pred<(U, V)> {
return { q in AND1(p: p, q: q) }
}
that takes as parameter a predicate p: Pred<U>, where Pred<U> is a typealias for (T) -> Bool:
typealias Pred<T> = (T) -> Bool
The return of ASSUM is a Predicate transformer closure of type (Pred<U>)->Pred<(U,V)>.
However the compiler return the following error :
Passing non-escaping parameter 'q' to function expecting an #escaping closure
I understand that the function AND1 as defined requests an escaping parameter :
func AND1<U, V>(p: #escaping Pred<U>, q: #escaping Pred<V>) -> Pred<(U, V)> {
return { (x, y) in (p(x) && q(y)) }
}
but I did not succeed in explicitly making q in { q in AND1(p: p, q: q) } escaping.
How can I fix this?
You must explictly add the #escaping attribute to the argument of the return type closure of ASSUM:
typealias Pred<T> = (T)->Bool
func AND1<U, V>(p: #escaping Pred<U> , q: #escaping Pred<V>) -> Pred<(U, V)> {
return { (x,y) in (p(x) && q(y)) }
}
func ASSUM<U, V>(p: #escaping Pred<U>) -> (#escaping Pred<V>) -> Pred<(U, V)> {
/* ^ note: I believe you
want V here, not U */
return { AND1(p: p, q: $0) }
}
In the returned closure, q (anonymous $0 argument) is correctly inferred as #escaping (and needn't be explicitly marked as such, as pointed out by #Hamish, thanks!).
Note also that the generic type V in ASSUM must be inferred by explicit type annotation (or conversion) by the caller, as it is not included in any of the arguments to ASSUM.
/* example usage */
let foo = { $0 < 2 }
let bar = { $0 != "bar" }
let fooAnd: (#escaping Pred<String>) -> Pred<(Int, String)> = ASSUM(p: foo)
let fooAndBar = fooAnd(bar)
print(fooAndBar((1, "foo"))) // true
print(fooAndBar((1, "bar"))) // false
print(fooAndBar((2, "foo"))) // false
Finally, ALLCAPITAL function names is not in line with the Swift naming convention: you should prefer camelCase naming instead (see e.g. the Swift API guidelines for additional details).

Using #discardableResult for Closures in Swift

Swift 3 has introduced the #discardableResult annotation for functions to disable the warnings for an unused function return value.
I'm looking for a way to silence this warning for closures.
Currently, my code looks like this:
func f(x: Int) -> Int -> Int {
func g(_ y: Int) -> Int {
doSomething(with: x, and: y)
return x*y
}
return g
}
In various places I call f once to obtain a closure g which I then call repeatedly:
let g = f(5)
g(3)
g(7)
g(11)
In most places I'm only interested in the side effects of the nested call to doSomething, and not in the return value of the closure g. With Swift 3, there are now dozens of warnings in my project for the unused result. Is there a way to suppress the warnings besides changing the calls to g to _ = g(...) everywhere? I couldn't find a place where I could place the #discardableResult annotation.
I don't think there's a way to apply that attribute to a closure. You could capture your closure in another that discards the result:
func discardingResult<T, U>(_ f: #escaping (T) -> U) -> (T) -> Void {
return { x in _ = f(x) }
}
let g = f(5)
g(3) // warns
let h = discardingResult(g)
h(4) // doesn't warn
I was looking for an answer to this recently, and I've found another way (a newer way) to do this!
It could arguably be overkill for some simple problems, but I just thought that this is an interesting yet neat approach that's worth sharing.
Say you have a closure that doubles an integer value:
let double = { (int: Int) -> Int in
return int * 2
}
With Swift 5.0 (SE-0216) introducing the #dynamicCallable attribute, you can "wrap" your closure with #discardableResult by creating a dynamically callable class or struct as such:
// same for struct, except without the need of an initializer
#dynamicCallable
class DiscardableResultClosure<T, U> {
var closure: (T) -> U
#discardableResult
func dynamicallyCall(withArguments args: [Any]) -> U {
let arg = args.first as! T
return self.closure(arg)
}
// implicit for struct
init(closure: #escaping (T) -> U) {
self.closure = closure
}
}
double(5) // warning: result of call to function returning 'Int' is unused
let discardableDouble = DiscardableResultClosure(closure: double)
discardableDouble(5) // * no warning *
Even better, in Swift 5.2 (SE-0253), you can create a dynamically callable struct using a built-in callAsFunction method without going through the trouble of using the attribute #dynamicCallable (or using class) with its sometimes cumbersome declaration.
struct DiscardableResultClosure<T, U> {
var closure: (T) -> U
#discardableResult
func callAsFunction(_ arg: T) -> U {
return closure(arg)
}
}
let discardableDouble = DiscardableResultClosure(closure: double)
discardableDouble(5) // * no warning *

Curried infix operators in swift. Is it possible?

I am trying to implement function composition. At first I defined a function that is named compose.
func compose<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
This works great. For example if I have not and isEven functions like
func not(value: Bool) -> Bool {
return !value
}
func even(value: Int) -> Bool {
return value % 2 == 0
}
The odd function can be defined in terms of not and even like this:
func odd(value: Int) -> Bool {
return compose(not)(isEven)(value)
}
Then I decided to use a custom operator instead of compose function. The custom operator is ... At first I just copied compose function and changed it name to ... Here is how it looks like:
infix operator .. { associativity left }
func ..<A,B,C>(f:(B -> C))(g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
Here Xcode gives the error: "Unary operator implementation must have a 'prefix' or 'postfix' modifier"
After that I changed the operator to this:
infix operator .. { associativity left }
func ..<A,B,C>(f: (B -> C), g: (A -> B)) -> A -> C {
return { f(g($0)) }
}
And odd function to this:
func odd(value: Int) -> Bool {
return (not..even)(value)
}
Or as a closure:
let odd = not..even
And this code worked. Now I know maybe there is no benefit here to make .. operator curried here but I wonder why curried operators is not allowed? For example if + operator were defined as curried function we would make something like this:
let array = [1,2,3,4]
array.map((+1))
You're asking for something known as operator sections, or the ability to partially apply binary operators on the left or the right. Unfortunately, Swift allows only fully uncurried operators, which means you have to get a little creative. If we regard an operator as a binary function op : (A, A) -> A, then its curried form, curry-op : A -> A -> A, is simply a unary function returning a unary function. We can fake this with custom prefix and postfix operators that simulate right and left sectioning respectively.
Here's prefix and postfix +
prefix func +<A : protocol<IntegerLiteralConvertible, IntegerArithmeticType>>(r : A) -> (A -> A) {
return { l in l + r }
}
postfix func +<A : protocol<IntegerLiteralConvertible, IntegerArithmeticType>>(l : A) -> (A -> A) {
return { r in l + r }
}
This allows you to write code such as
let l = [Int](1...10) /// [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
l.map(+5) /// [6, 7, 8, 9, 10, 11, 12, 13, 14, 15]
instead of the old
l.map({ x in x + 5 })
Let's write some (incomplete) definitions for the terms in your question:
non-curried two-argument function: A function that takes two arguments and returns some value. Example: func add(a: Int, b: Int) -> Int
curried two-argument function: A function that takes one argument and returns another function that takes one argument and returns some value. Example: func add(a: Int)(b: Int) -> Int
infix (binary) operator: An operator that takes two operands, an lhs and an rhs argument, and returns some value. Example: func +(lhs: Int, rhs: Int) -> Int
prefix/postfix (unary) operator: An operator that takes a single operand, either after or before the operator, and returns some value. Example: func -(x: Int) -> Int
Curried functions are more akin to unary operators than binary ones; that's why Swift is complaining.