Using Swift function that a function that takes a generic sequence - swift

I'm picking swift up now and the generics are pretty different than what I'm used to. What is the right way to do something like this?
func createThing<T, Seq: Sequence>(_ type: T.Type, _ block : #escaping (_ sequence: Seq) -> Void) where Seq.Element == T {
// ...
}
enum MyEnum {
case A
case B
}
// error: generic parameter 'Seq' could not be inferred
createThing(MyEnum.Type, { sequence in
for i in sequence{
//...
}
})
I would love to just supply a generic type parameter directly with createThing<MyEnum>(...) but that apparently isn't something Swift can do and generics seem to work pretty different for protocols than they do everything else.

Seq is part of the generic signature of the createThing function, which means that the compiler either needs to be able to infer this from the calling context, or be explicitly be told what concrete implementation of Sequence should expect. Also placing the Sequence generic at the function level really limits what you can do within that function, since it cannot instantiate a protocol.
You can convert the (Seq) -> Void block to a (T) -> Void one, and move the sequence iteration in doSomething, this will remove the compile error. And while you're at it, you can add a default value for the type parameter, this will enable type inferring and automatic filling of that parameter
func createThing<T>(_ type: T.Type = T.self, _ block: (T) -> Void) {
// ...
// assuming sequence is create above
sequence.forEach(block)
}
enum MyEnum {
case a
case b
}
// a dedicated function for processing items also means better structured code :)
func processEnum(_ value: MyEnum) {
// do your stuff
}
// you can now pass only the second argument
createThing(processEnum)

Related

What is the Swift compiler doing with my return type? Is it somehow casting?

I have a method:
func allRegions() -> [MappedRegion] {
return self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
}
I was frankly surprised this worked. I'm doing lazy stuff here, but it's apparently having a lazy sequence that turns into a sequence of MappedRegion be the same.
Then I was doing some poor mans timing and modified the function to read:
func allRegions() -> [MappedRegion] {
let startTime = Date()
let result = self.items.lazy.compactMap { item in item.valveAny }.flatMap { valve in valve.regions }
self.sumRender += (Date() - startTime)
return result
}
But that created an error:
Cannot convert return expression of type 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<LazySequence<[StatusRowItem]>.Elements, ValveAbstract?>>, ValveAbstract>.Elements, [MappedRegion]>>>' (aka 'LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<LazyFilterSequence<LazyMapSequence<Array<StatusRowItem>, Optional<ValveAbstract>>>, ValveAbstract>, Array<MappedRegion>>>>') to return type '[MappedRegion]'
That was initially a surprise. I found that if I specified the return type of result as [MappedRegion] all was happy (e.g. let result:[MappedRegion] = ...).
What is going on here? I get that the original one line function is inferring the result type as [MappedRegion], so I'm probably not getting much benefits from the lazy use. But what confuses me, is that this coercion from a lazy sequence to a fixed array automagically is reminiscent of casting in C, and I thought that Swift didn't do casting?
No, there is no casting going on. There are simply two different flatMap functions being called. LazyMapSequence has two flatMap(_:) functions (well, technically four, but two are deprecated).
In your first code block, this function is inferred (because this version of flatMap has a return type that matches your allRegions function's return type):
func flatMap<SegmentOfResult>(_ transform: (Element) throws -> SegmentOfResult) rethrows -> [SegmentOfResult.Element] where SegmentOfResult : Sequence
And in your second code block, this function is inferred (because there is no type annotation on your local variable that's forcing it to choose the above version of flatMap):
func flatMap<SegmentOfResult>(_ transform: #escaping (Element) -> SegmentOfResult) -> LazySequence<FlattenSequence<LazyMapSequence<LazyMapSequence<Base, Element>, SegmentOfResult>>> where SegmentOfResult : Sequence

Swift optional promotion vs generic overload resolution

Please consider the following code:
protocol P {}
class X {}
class Y: P {}
func foo<T>(_ closure: (T) -> Void) { print(type(of: closure)) }
func foo<T>(_ closure: (T) -> Void) where T: P { print(type(of: closure)) }
let xClosure: (X?) -> Void = { _ in }
foo(xClosure) // prints "(Optional<X>) -> ()"
let yClosure: (Y?) -> Void = { _ in }
foo(yClosure) // prints "(Y) -> ()"
Why does the foo(yClosure) call resolve to the version of foo constrained to T: P?
I understand why that version prints what it prints,
what I don't see is why it gets called instead of the other one.
To me it seems that the non-P version would be a better match for T == (Y?) -> Void.
Sure, the constrained version is more specific, but it requires conversion
(an implicit conversion from (Y?) -> Void to (Y) -> Void),
while the non-P version could be called with no conversion.
Is there a way to fix this code in a way such that the P-constrained version gets called
only if the parameter type of the passed-in closure directly conforms to P,
without any implicit conversions?
Specificity seems to always trump variance conversions, according to my experiments. For example:
func bar<T>(_ x: [Int], _ y: T) { print("A") }
func bar<T: P>(_ x: [Any], _ y: T) { print("B") }
bar([1], Y()) // A
bar is more specific, but requires a variance conversion from [Int] to [Any].
For why you can convert from (Y?) -> Void to (P) -> Void, see this. Note that Y is a subtype of Y?, by compiler magic.
Since it is so consistent, this behaviour seems to be by design. Since you can't really make Y not a subtype of Y?, you don't have a lot of choices if you want to get the desired behaviour.
I have this work around, and I admit it's really ugly - make your own Optional type. Let's call it Maybe<T>:
enum Maybe<T> {
case some(T)
case none
// implement all the Optional methods if you want
}
Now, your (Maybe<Y>) -> Void won't be converted to (P) -> Void. Normally I wouldn't recommend this, but since you said:
in the real-world code where I encountered this, the closure has multiple params, any of them can be optional, so this would lead to a combinatorial explosion.
I thought reinventing Optional might be worth it.

Reduce array of closures into single closure

Suppose I have an array of closures which can all be composed with one another (i.e., endomorphisms, their input and output types are the same). How can I compose these closures into a single closure?
For reference, I was trying to design something like the following.
struct MyType {
typealias MyClosure: (T) -> T
private var myClosures: [MyClosure] = [ ... ]
public var closure: MyClosure {
get {
return ? // somehow compose all of myClosures into a single closure here
}
}
}
My first thought was to use reduce, à la myClosures.reduce(STARTING) { a, b in b(a) },
but this requires a starting value to be supplied, and then successively applies the closures to it. I don't want to apply the closures to anything (yet), but just synthesize the private list of closures into a single, public closure which can be applied later. Given the way reduce is
defined, I expect this would look something like
myClosures.reduce(identity) { a, b in compose(a, b) }
func identity(_ input: T) { return input }
func compose(a: MyClosure, b: MyClosure) -> MyClosure { return b(a) }
but the type of b(a) is T, not (T) -> T. How can this be accomplished? Is this a better way of going about closure composition?
Edit: My original answer misunderstood what your problem was. But seeing as my original answer might be useful to future readers, I'll leave it at the bottom.
Your compose function is nearly there! b(a) does not compile because MyClosure does not take another MyClosure. b(a) is invoking the closure ("function application"). not composition. Since compose returns a closure, why not return a closure? A typical closure looks like this in Swift:
{ (param) in return doSomethingTo(param) }
So let's return that!
return { (x) in return b(a(x)) }
This can be simplified to:
{ b(a($0)) } // "return" can be omitted as well!
This page (among other things) tells you how and when you can simplify closure syntaxes.
Original answer:
Using reduce is the correct choice here. The reduction operation is composition, so let's write a compose function first:
func compose<T>(_ x: #escaping (T) -> T, _ y: #escaping (T) -> T) -> (T) -> T {
{ y(x($0)) } // or { x(y($0)) } if you want it the other way
}
Then, we reduce. What's the identity? The identity is something that has these properties:
compose(identity, anything) == anything
compose(anything, identity) == anything
What function does that? The identity function!
So we get:
func reduceClosures<T>(_ closures: [(T) -> T]) -> (T) -> T {
closures.reduce({ $0 }, compose)
}

Infer closure return type from closure body when working with generics

I think best if I start with an example:
class Test<T> {
func test(closure: (T) -> Void) { }
func test(closure: (T) -> T) { }
func test(closure: (T) -> Test<T>) { }
}
Test<Int>().test { a in }
The code above gives the following error:
error: ambiguous use of 'test'
This is because the Swift compiler doesn't know to which one of the three methods is should map the call to. But from the closure body it's quite clear that it returns a Void, so it should pick the first method.
Looks like the Swift compiler cannot determine to which method overload to map the call to based on the closure body. If I explicitly specify the closure signature, then the problem goes away:
Test<Int>().test { (a: Int) -> Void in }
My question is: can I somehow instruct Swift to pick-up the correct overload for short-hand closure expressions like the one in discussion, or will I have to explicitly declare the closure signature?
Actually, it seems that I was pushing the compiler limits too hard (as #Martin R pointed in the comments). The { a in } closure was kinda incomplete, since the compiler had no statements to infer the closure return type from.
This works:
Test<Int>().test { (a: Int) -> Void in () }
Same as the following:
func doNothing() { }
Test<Int>().test { (a: Int) -> Void in doNothing() }
In the above examples the compiler is provided with the minimum amount of information to determine which overload to pick.

Swift Generic constraints in init

I have generic and I want to be able to initialize it with specific constrains. The constraints are only there for initialization. The rest of the class doesn't care. Here is a simplified example:
struct Generic<T> {
let compare: (T, T) -> Bool
init<T: Equatable>(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
insert(data)
}
init(compareHandler: (T, T) -> Bool, data[T]) {
compare = self.compareHandler
insert(data)
}
}
You can see there's two initializers. The second one obviously works fine. However, in the first one the local type T is mismatched with the struct's generic Type. So, for example, attempting to insert data I get Cannot invoke 'insert' with an argument list of type '([T])'. Is it possible for me to specialize the Struct's generic type only for the initialization or a specific function?
Note, I've already tried init<T where T:Equatable>(data: [T]) to the same effect.
Update
I'm using the following workaround: I create a top level function and removing the specialized init:
func equatableHandler<T: Equatable>(left: T, right: T) -> Bool {
return left == right
}
Clients of the struct can initialize using: Generic(compareHandler: equatableHandler, data: data)
It's not quite the "convenience" of using a specialized init, but I suppose it works well enough for my purposes. I'm not a fan of creating top-level functions, but the generic is used so often for "Equatable" generics that it makes sense for me to define the handler once for clients to use.
The problem is that the first init method
init<T: Equatable>(data: [T])
introduces a local type placeholder T which hides (and is completely
unrelated to) the placeholder T of the Generic type, so it
is essentially the same problem as in Array extension to remove object by value.
As of Swift 2 you can solve that with a "restricted extension":
extension Generic where T : Equatable {
init(data: [T]) {
let handler: (T, T) -> Bool = { $0 == $1 }
compare = handler
// ...
}
}
For Swift 1.x the only solution is probably to define a global helper
function
func makeGeneric<T : Equatable>(data: [T]) -> Generic<T> {
return Generic(compareHandler: { $0 == $1 }, data: data)
}
(and I could not think of a sensible name for the function :).