converting a function that accepts closures to accept functions - swift

I have a function that accepts a closure as an argument
public func createSelector<Input: Hashable, Output, A>(_ selectorA: #escaping (Input) -> A, _ combine: #escaping (A) -> Output) -> (Input) -> Output {
return memoize({ combine(selectorA($0)) })
}
A use case is something like this
let getStore = { (store: AppState?) -> FeedState? in store?.feed }
let getFeedItems = createSelector(getStore) { (state: FeedState?) -> [Post] in state?.posts ?? [] }
This is used to select a piece of state from a ReSwift store and return results after running a memoize function.
Xcode seems to struggle with auto complete when using this closure pattern
When I expect it to be able to show props as follows
It was suggested to me that writing my closures as functions will prevent this issue.
As such, I am trying to convert the above function to work with functions to see if this helps.
I am confused how the above pattern can be refactored to support functions instead and would appreciate any advice.
Thank you.
Edit:
This is an example attempt:
func getStoreFunc(_ state: AppState?) -> FeedState? {
return state?.feed
}
func getFeedItemsFunc(_ fn: #escaping (AppState?) -> FeedState?) -> [Post] {
return createSelector(fn, { (state: FeedState?) -> [Post] in
return state?.posts ?? []
})
}
However this produces and error of
Cannot convert return expression of type '(AppState?) -> [Post]' to
return type '[Post]'
on my getFeedItemsFunc

Your createSelector(_:_:) function takes two closures. However, Swift lets you pass functions in place of closures so long as the types match.
In your code, you declared one closure beforehand (getStore) and wrote the other one using trailing closure syntax when you called the createSelector(_:_:) method. However, functions can't be declared using this syntax. So I created a function called getPostsFunc(_:) that replaces your second closure.
// corresponds to:
//let getStore = { (store: AppState?) -> FeedState? in store?.feed }
func getStoreFunc(_ state: AppState?) -> FeedState? {
return state?.feed
}
//corresponds to:
//{ (state: FeedState?) -> [Post] in state?.posts ?? [] }
func getPostsFunc(_ state: FeedState?) -> [Post] {
return state?.posts ?? []
}
//This is the same as your `getFeedItems`
let getFeedItems = createSelector(getStoreFunc, getPostsFunc)
Hope this helps!

Related

Swift syntax explanation with compact map

I did find following code while examine code:
override func layoutAttributesForElements(in rect: CGRect) -> [UICollectionViewLayoutAttributes]? {
return super.layoutAttributesForElements(in: rect)?
.compactMap { $0.copy() as? ParallaxLayoutAttributes }
.compactMap(prepareAttributes)
}
private func prepareAttributes(attributes: ParallaxLayoutAttributes) -> ParallaxLayoutAttributes {
// Lot of code doing stuff with attributes
return attributes
}
So, actually what i want to ask is, that compact is function declared as following:
#inlinable public func compactMap<ElementOfResult>(_ transform: (Element) throws -> ElementOfResult?) rethrows -> [ElementOfResult]
Here in example, we pass just function, without arguments:
.compactMap(prepareAttributes)
That completely bend my mind, because, well, prepareAttributes function declared like this (with argument you have to pass):
private func prepareAttributes(attributes: ParallaxLayoutAttributes) -> ParallaxLayoutAttributes
So, why code above compiles and what how exactly .compactMap(prepareAttributes)
runs when you did not pass an argument for prepareAttributes function?
In the call .compactMap(prepareAttributes), you pass in the function, prepareAttributes to compactMap as a closure. Since prepareAttributes takes a single input argument whose type matches the closure variable of compactMap, the compiler can automatically infer that it needs to pass $0 to prepareAttributes.
So essentially, .compactMap(prepareAttributes) is shorthand for
.compactMap {prepareAttributes(attributes: $0) }
A simple example of the same behaviour with map that is quite often used is to map over a type that you then pass into an init, which you could write as .map { MyType(input: $0) } or simplify to .map(MyType.init).
struct MyInt {
let value: Int
init(value: Int) {
self.value = value
}
}
let ints = [1,2,3]
let myInts = ints.map(MyInt.init) // same as `ints.map { MyInt(value: $0) }

Swift type of shuffle()

I want to test a function, passing in a shuffle function so I can Unit test the function adequately. In other words:
func testme(testArr: [Int], shufflefunction : Shufflefunction = .shuffle) -> [Int] {
return tetsArr.shufflefunction
}
I know the syntax is incorrect; and that is the question.
What is the correct type of the shuffled function so I can make a reusable function for any particular shuffle implementation, as passed in the function above.
The second part of the problem is how to pass the standard shuffle() implementation as a default parameter for testing this function.
If you look at Array.shuffled, you will see that it is actually a function that takes an array, and returns a () -> [T]:
Therefore, the type of Array.shuffled could be written as
(([T]) -> (() -> [T]))
We can then use this as our parameter type:
func testShuffle<T>(array: [T], function: (([T]) -> (() -> [T])) = Array.shuffled) {
let shuffleFunction = function(array)
let shuffledArray = shuffleFunction()
// do stuff with shuffledArray...
}
// usage
extension Array {
func myCustomShuffled() -> [Element] {
// ...
}
}
let arr = [1,2,3,4,5,6,7]
testShuffle(array: arr, function: Array.myCustomShuffled)
Note that the same approach doesn't work with Array.shuffle (the mutating version), because Swift doesn't support partial applications on mutating functions.
You can also write the parameter type as ([T]) -> [T], then you would have to pass the default parameter like this:
func testShuffle<T>(array: [T], function: ([T]) -> [T] = { $0.shuffled() }) {
let shuffledArray = function(array)
}

Swift closures - force a closure to always complete

Is it possible to force a closure to be completed? In the same way that a function with a return value MUST always return, it would be ace if there was a way to force a closure to contain the syntax necessary to always complete.
For example, this code will not compile because the function does not always return a value:
func isTheEarthFlat(withUserIQ userIQ: Int) -> Bool {
if userIQ > 10 {
return false
}
}
In the exact same way, I would like to define a function with a closure, which will also not compile if the closure never returns. For example, the code below might never return a completionHandler:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
if userIQ > 10 {
completionHandler(false)
}
}
The code above compiles, but I was wondering if there is a keyword which enforces that the closure sends a completion handler in all cases. Maybe it has something to do with the Void in the above function?
No, there is no language construct that will result in a compiler error if you forget (or don't need) to call the completion handler under all possible conditions like a return statement.
It's an interesting idea that might make a useful enhancement to the language. Maybe as a required keyword somewhere in the parameter declaration.
There is no special keyword for what you want. But there is an interesting approach you can take into consideration, that won't compile:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
let result: Bool
defer {
completionHandler(result)
}
if userIQ > 10 {
result = false
}
}
that will do and is completionHandler is forced to be called:
func isTheEarthFlat(withUserIQ userIQ: Int, completionHandler: (Bool) -> Void) {
let result: Bool
defer {
completionHandler(result)
}
if userIQ > 10 {
result = false
} else {
result = true
}
}
Not sure it's a good pattern to use.
Here is an interesting technique I thought of. You define GuarenteedExecution and GuarenteedExecutionResult types.
A GuarenteedExecution is a wrapper around a closure, which is to be used in a context where the execution of the closure must be guaranteed.
The GuarenteedExecutionResult is the result of executing a GuarenteedExecution. The trick is to have a desired function, e.g. isTheEarthFlat, return a GuarenteedExecutionResult. The only way to obtain a GuarenteedExecutionResult instance is by calling execute(argument:) on a GuarenteedExecution. Effectively, the type checker features responsible for guaranteeing a return, are now being used to guarantee the execution of GuarenteedExecution.
struct GuarenteedExecutionResult<R> {
let result: R
fileprivate init(result: R) { self.result = result }
}
struct GuarenteedExecution<A, R> {
typealias Closure = (A) -> R
let closure: Closure
init(ofClosure closure: #escaping Closure) {
self.closure = closure
}
func execute(argument: A) -> GuarenteedExecutionResult<R> {
let result = closure(argument)
return GuarenteedExecutionResult(result: result)
}
}
Example usage, in a seperate file (so as to not have access to GuarenteedExecutionResult.init):
let guarenteedExecutionClosure = GuarenteedExecution(ofClosure: {
print("This must be called!")
})
func doSomething(guarenteedCallback: GuarenteedExecution<(), ()>)
-> GuarenteedExecutionResult<()> {
print("Did something")
return guarenteedCallback.execute(argument: ())
}
_ = doSomething(guarenteedCallback: guarenteedExecutionClosure)

Trouble with non-escaping closures in Swift 3

I have an extension Array in the form of:
extension Array
{
private func someFunction(someClosure: (() -> Int)?)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
But I'm getting the error: Passing non-escaping parameter 'someOtherClosure' to function expecting an #escaping closure.
Both closures are indeed non-escaping (by default), and explicitly adding #noescape to someFunction yields a warning indicating that this is the default in Swift 3.1.
Any idea why I'm getting this error?
-- UPDATE --
Screenshot attached:
Optional closures are always escaping.
Why is that? That's because the optional (which is an enum) wraps the closure and internally saves it.
There is an excellent article about the quirks of #escaping here.
As already said, Optional closures are escaping. An addition though:
Swift 3.1 has a withoutActuallyEscaping helper function that can be useful here. It marks a closure escaping only for its use inside a passed closure, so that you don't have to expose the escaping attribute to the function signature.
Can be used like this:
extension Array {
private func someFunction(someClosure: (() -> Int)?) {
someClosure?()
}
func someOtherFunction(someOtherClosure: () -> Int) {
withoutActuallyEscaping(someOtherClosure) {
someFunction(someClosure: $0)
}
}
}
let x = [1, 2, 3]
x.someOtherFunction(someOtherClosure: { return 1 })
Hope this is helpful!
The problem is that optionals (in this case (()-> Int)?) are an Enum which capture their value. If that value is a function, it must be used with #escaping because it is indeed captured by the optional.
In your case it gets tricky because the closure captured by the optional automatically captures another closure. So someOtherClosure has to be marked #escaping as well.
You can test the following code in a playground to confirm this:
extension Array
{
private func someFunction(someClosure: () -> Int)
{
// Do Something
}
func someOtherFunction(someOtherClosure: () -> Int)
{
someFunction(someClosure: someOtherClosure)
}
}
let f: ()->Int = { return 42 }
[].someOtherFunction(someOtherClosure: f)

How to create function with two closures as params in Swift?

I need to translate such a func from Objective-C to Swift language. But can't find an example and can't get how to send 2 closures into func in Swift.
For example, original function in Objective-C:
- (void)getForDemoDataWithToken:(Token *)token
onSuccess:(void(^)(NSArray *demoData))success
onFailure:(void(^)(NSError *error))failure {
}
I know to send 1 closure as param:
getForDemoDataWithToken(token) {(success: String) -> Void in
// some code here
print(success)
}
But, how to send two closures?
Thank you
What about this?
Declaration
func getForDemoDataWithToken(
token: Token,
onSuccess: (demoData:NSArray?) -> (),
onFailure: (error:NSError?) -> ()) {
}
Invocation
getForDemoDataWithToken(Token(),
onSuccess: { (demoData) -> () in
},
onFailure: { (demoData) -> () in
}
)
A more Swifty approach
I usually see Swift code where only one closure is used. So instead of 2 distinct onSuccess and onFailure closures you could have just completion.
Next we should remember that NSArray is compatible with Swift but it's not the Swiftest way to use an array.
Let's see an example where the 2 concepts above are applied.
func getForDemoData(token:Token, completion:(data:[Foo]?, error:NSError?) -> ()) {
}
You can invoke it with the trailing closure syntax.
getForDemoData(Token()) { (data, error) -> () in
if let data = data where error == nil {
// success!
} else {
// oh no... something wrong here
}
}
You should pass the closures as normal parameters, like this:
func acceptsTwoClosures(
onSuccess onSuccess: (success: String) -> Void,
onFailure: (failure: String) -> Void) {
onSuccess(success: "Ook")
onFailure(failure: "Eek")
}
acceptsTwoClosures(
onSuccess: { print("Success: \($0)") },
onFailure: { print("Failure: \($0)") }
)
// In the playground the above prints:
//
// Success: Ook
// Failure: Eek
The way that you used in the question is called trailing closure, and it only works for the closures that are the last arguments in the function signature.
From the documentation:
If you need to pass a closure expression to a function as the function’s final argument and the closure expression is long, it can be useful to write it as a trailing closure instead. A trailing closure is a closure expression that is written outside of (and after) the parentheses of the function call it supports.
For example, you could also re-write my suggested snippet from above like this:
acceptsTwoClosures(onSuccess: { print("Success: \($0)") }) {
print("Failure: \($0)")
}
.. as you can see, I can pass the second (i.e. the last) closure outside of acceptsTwoClosures call as a trailing closure, but I still have to pass the first one as a normal parameter.