Swift type of shuffle() - swift

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)
}

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) }

converting a function that accepts closures to accept functions

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!

Swift mutating Function as first class value

I can have a function to swap the first two elements of an array:
func swapFirstTwo(array: inout [Int]) {
if array.count >= 2 {
array.swapAt(0, 1)
}
}
typealias Swapper = (inout [Int]) -> ()
// And I can have a variable = the function
let swapThem: Swapper = swapFirstTwo
// And it works like this:
var array = [1,2,3]
print(array)
swapThem(&array)
print(array)
// But I'm allergic to Global functions!
// It would be more swifty to have:
extension Array where Element == Int {
mutating func swapFirstTwo2() {
if count >= 2 {
swapAt(0, 1)
}
}
}
typealias Swapper2 = (inout [Int]) -> () -> ()
// But when I do this:
let swapThemAgain: Swapper2 = Array.swapFirstTwo2
// I get the error:
// Partial application of 'mutating' method is not allowed; calling the function has undefined behavior and will be an error in future Swift versions
var array2 = [1,2,3]
print(array2)
array2.swapFirstTwo2()
print(array2)
// This in fact works but I've tried similar things and sometimes they appear to be unstable.
// How can I achieve doing: array2.swapFirstTwo2() without getting the error?
This in fact works but I've tried similar things and sometimes they appear to be unstable.
Also the compiler warning needs to be heeded.
How can I achieve doing: array2.swapFirstTwo2() without getting the warning/error?
The reason why you get a warning (and soon to be an error in Swift 5 mode) on:
extension Array where Element == Int {
mutating func swapFirstTwo2() {
if count >= 2 {
swapAt(0, 1)
}
}
}
typealias Swapper2 = (inout [Int]) -> () -> ()
let swapThemAgain: Swapper2 = Array.swapFirstTwo2
is due to the fact that inout arguments are only valid for the duration of the call they're passed to, and therefore cannot be partially applied.
So if you were to call the returned (inout [Int]) -> () -> () with &array2, you would get back a () -> () which now has an invalid reference to array2. Attempting to call that function will yield undefined behaviour, as you're trying to mutate an inout argument outside of the window where it's valid.
This problem will be fixed if/when unapplied instance methods get flat signatures, as Array.swapFirstTwo2 will instead evaluate to a (inout [Int]) -> ().
But in the mean time, you can workaround the issue by using a closure instead:
typealias Swapper2 = (inout [Int]) -> ()
let swapThemAgain: Swapper2 = { $0.swapFirstTwo2() }
var array2 = [1,2,3]
print(array2) // [1, 2, 3]
array2.swapFirstTwo2()
print(array2) // [2, 1, 3]

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)

parameters with optional closures in swift

I'm using optional closures, but can't find a way to pass on a parameter.
Searched everywhere, tried all suggestions, but can't get it to work.
My code:
func DoAlert(title: String
, message: String
, actions: String
, sender: AnyObject?
, Ctlr : UIViewController
, SegueString: String?
, YesClosure: ()->() = {}
, NoClosure: ()->() = {}
, StartClosure: ()->() = {}
, EndClosure: ()->() = {}
) {
if (actions.rangeOfString("Ok") != nil {
alert.addAction(UIAlertAction(title: "OK", style: .Default ) { action -> Void in
EndClosure()
})}
} // end function
I want to add a closure for Ok, where the 'self' parameter is needed.
Something like below:
// add to func doAlert:
, OkClosure: (AnyObject)->() = {}
// add to action Ok (before the EndClosure:
OkClosure(sender!)
Getting error on first line:
AnyObject is not subtype of ()
If I leave AnyObject out of first line, Getting error:
Cannot convert the expression's type 'AnyObject' to type '() => ()'
All other trials give me similar 'Tuple' errors.
How do I code the passing of parameters in the optional closures in my code?
Firstly, to use closures as an argument for a function, you should declare them like so:
func myFunc(closure: (Int) -> Void) {
// Now I can call closure like so:
let myInt = 10
closure(myInt)
}
(As pointed out by #Airspeed Velocity, the parenthesis around Int are not strictly required because there is only one argument. Whether you include them is just personal preference)
Secondly, you can modify the previous function to include an optional closure, as follows:
(Note the ? and parenthesis around the closure that indicate the closure is an optional, not the return type)
func myFunc(closure: ((Int) -> Void)?) {
// Now when calling the closure you need to make sure it's not nil.
// For example:
closure?(10)
}
Thirdly, to add a default value of nil, which is what it looks like you're trying to do with the = {} on the end of YesClosure: ()->() = {}, you could do:
func myFunc(closure: ((Int) -> Void)? = nil) {
// Still need to make sure it's not nil.
if let c = closure {
c(10)
}
}
Finally, just as a note, you can set the names of the arguments of the closure, which can make it easier to identify what you're passing to the closure when calling it. For example:
(Note - here parenthesis are required around value: Int)
func myFunc(closure: ((value: Int) -> Void)) {
closure(value: 10)
}
Even more finally, you could use typealias. According to the documentation:
A type alias declaration introduces a named alias of an existing type into your program.
Here's an example of how to use it with a closure:
typealias MyClosureType = () -> Void
func myFunc(closure: MyClosureType) {
closure()
}
Hope that helps!
I think I found it. I can't use parameters in the closure when I call func. In func itself I need to define the parameters used (closure: (sender: AnyObject) -> Void), make sure the variables are defined (or provided as a separate parameter) and add them to the closure call.
#IBAction func buttonPressed(sender: AnyObject) {
myFunc (sender, doClosure)
}
func myFunc(sender: AnyObject, closure: (sender: AnyObject) -> Void) {
// Now I can call closure like so:
closure (sender: sender)
}
func doClosure(sender: AnyObject) {
println("sender = \(sender)")
}