Search code examples
swiftswift-playground

Why do some expressions log results and others just show iteration counts?


I haven't used playgrounds very much with Swift. Mostly I've been using it in projects, so I'm a little lost in dealing with playgrounds.

I've got this test code in a small playground:

let array = [7, 3, 4, 9, 2, 12, 5]
let firstSorted = array.sorted(<)
let secondSorted = sorted(array, <)
let thirdSorted = array.sorted { $0 < $1 }

The output that's shown on the right shows the sorted array output next to firstSorted and secondSorted. The output next to thirdSorted just says (15 times) however.

Why? And how do I see the output, without adding a separate println command to log the output?

The third form has a trailing closure with the parameters specified by their positions.

The other two are a still shorter form that takes just the comparison operator, which happens to match the signature of the closure that's needed.

Another question: (this time about the language, not playgrounds) Why do both the sorted(array, <) and array.sorted(<) forms work? The first is a global function that takes 2 parameters, and the second form is a method on the Array class.


Solution

  • It’s because the closure you are passing into sorted is called by sorted to do 13 element comparisons as it sorts the array, plus the call to sorted itself. Whenever a line of code you’ve written is run in the playground it displays either the result of the expression or a count. Because the same line is evaluated multiple times, the IDE can’t show everything so it just shows the count.

    If you break it out into multiple lines, you can see the result from sorted, as well as the results of the 13 evaluations of $0 < $1:

    Image showing 13 executions plus result

    I guess the IDE could take the approach that the outermost result is the most interesting, and show that, but that might hide the information that your closure is being called multiple times.

    As to the second question: the global 2-argument version of sorted is more general. It sorts any kind of sequence:

    // they should probably rename this placeholder to S...
    func sorted<C : SequenceType>
      (source: C, isOrderedBefore: (C.Generator.Element, C.Generator.Element) -> Bool) 
      -> [C.Generator.Element]
    

    so you can pass in anything that conforms to SequenceType:

    // results in [4,3,2,1,0]
    sorted(0..<5, >)  
    
    // results in [(3,"bob"),(2,"fred")] because dictionary’s 
    // SequenceType representation is unordered pairs
    sorted([2:"fred",3:"bob"]) { $0.1 < $1.1 }
    

    Also, since the global function can overload based on constrained inputs, there can be an overloaded version that doesn’t need a comparator at all if the input sequence’s element is Comparable:

    func sorted<C : SequenceType where C.Generator.Element : Comparable>
      (source: C) -> [C.Generator.Element]