2

When trying the following in the playground, I get the following error:

Cannot invoke 'sort' with an argument list of type '([Int], (Int, Int) -> Bool)'

let stuff = [1, 2, 3]
var sortedStuff = sort(stuff, { (left: Int, right: Int) -> Bool in left < right })

Am I doing something wrong?

1
  • Wow... Apple still hasn't updated their iBook... I just harassed them about it on Twitter, so hopefully they'll fix it... we'll see. Commented Oct 1, 2014 at 23:39

1 Answer 1

7

sort() sorts an array in-place:

var stuff = [3, 2, 1]
sort(&stuff, { (left: Int, right: Int) -> Bool in left < right })
println(stuff)   // [1, 2, 3]

The first argument of sort() must be the address of a variable array (and it does not return a value). This causes the (misleading) error message, as you are passing an array as the first argument.

What you probably want to use is sorted(), which does not modify the original array and returns a new sorted array:

let stuff = [3, 2, 1]
var sortedStuff = sorted(stuff, { (left: Int, right: Int) -> Bool in left < right })
println(stuff)          // [3, 2, 1]
println(sortedStuff)    // [1, 2, 3]

The function names have changed in one of the earlier beta releases, as mentioned in release notes

Important Changes, Issues Resolved in Xcode 6 beta 1–3
...
The global sort function now mutates its first argument, and a new sorted function always returns a new collection.

so some tutorials may be out-of-date. The Swift books however are regularly updated, so you might want to download a current version.

As mentioned in the comments, you can shorten the closure notation in various ways:

let sortedStuff = sorted(stuff, { left, right in left < right })  // Inferring type from context
let sortedStuff = sorted(stuff, { $0 < $1 })  // Shorthand argument names
let sortedStuff = sorted(stuff, <)  // Using an operator function

All this is described in detail in the "Closures" chapter of the Swift book.


Update for Swift 2 (Xcode 7): Returning a sorted array is called "sort" again, but it is a (protocol extension) method now instead of a global function:

let stuff = [3, 2, 1]
let sortedStuff = stuff.sort(<)
print(sortedStuff)   // [1, 2, 3]

and sorting an array in place has been renamed to "sortInPlace":

var stuff = [3, 2, 1]
stuff.sortInPlace(<)
print(stuff)   // [1, 2, 3]
Sign up to request clarification or add additional context in comments.

4 Comments

Also shorthand: sort(&stuff) { $0 < $1 } and var sortedStuff = sorted(stuff) { $0 < $1 } where $x revers to the left and right by position by index.
Even-shorter-hand: sort(&stuff, <) or sorted(stuff, <). You can pass a function or method anywhere a closure is expected, and that includes standard library functions and operators.
Also, since the answer isn't 100% clear on this: the reason your code doesn't work is that you're calling sort (which returns nothing) instead of sorted (which returns an array). The compiler is giving you the wrong error message (it's obliquely trying to tell you that the expected return type of your function call is not the type of the variable you're assigning it to) -- filing a bug would be a good idea.
@rickster: Assigning the void return value of sort() to a variable causes only a warning. The error is that sort() is called with a (constant) array instead of the address of a variable array. - Thanks to both of you for the feedback, I have tried to improve the answer.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.