Beta 6: flatten #swiftlang

The new flatten function is an odd creature. You’d think it would work like flatMap and it kind of sort of does but not entirely.

Here’s a quick example:

let array = [[1], [2, 3, 4], [5], [6, 7]]
print(array.flatMap({$0})) 
    // [1, 2, 3, 4, 5, 6, 7]
print(array.flatten()) 
    // FlattenBidirectionalCollection<Array<Array<Int>>>(_base: [[1], [2, 3, 4], [5], [6, 7]])
print(Array(array.flatten())) 
    // [1, 2, 3, 4, 5, 6, 7]

The flatten function returns a new seemingly lazy collection. I’m guessing it’s fairly similar to:

print(array.lazy.flatMap({$0}))
    // Swift.LazyMapCollection<Swift.Array<Swift.Array<Swift.Int>>, Swift.Array<Swift.Int>>(_base: [[1], [2, 3, 4], [5], [6, 7]], _transform: (Function))))

And like most collection / sequences, you can iterate over the results or force them to an array, etc.

There are actually 6 different versions of flatten in beta 6, which seem to start with collections of collections and build from there. The fourth of these is a real doozy.

  • extension CollectionType where Generator.Element : CollectionType
  • extension CollectionType where Generator.Element : CollectionType, Index : BidirectionalIndexType, Generator.Element.Index : BidirectionalIndexType 
  • extension LazyCollectionType where Generator.Element : CollectionType, Elements.Generator.Element : CollectionType, Generator.Element == Elements.Generator.Element
  • extension LazyCollectionType where Generator.Element : CollectionType, Index : BidirectionalIndexType, Generator.Element.Index : BidirectionalIndexType, Elements.Generator.Element : CollectionType, Elements.Index : BidirectionalIndexType, Elements.Generator.Element.Index : BidirectionalIndexType, Generator.Element == Elements.Generator.Element
  • extension LazySequenceType where Elements.Generator.Element == Generator.Element, Generator.Element : SequenceType
  • extension SequenceType where Generator.Element : SequenceType

More complex items can be called with flatten() but don’t necessarily return the thing you might expect:

let complexerArray = [[[1]], [[2]], [[3]], [[4, 5]]]
print(Array(complexerArray.flatten())) 
    // [[1], [2], [3], [4, 5]]

You can chain .flatten().flatten() to get [1, 2, 3, 4, 5] in this example but you can’t apply the function to an already flat collection.

I’m sure there’s a deeply compelling reason to prefer flatten over flatMap for simple flattening (it’s certainly easier to incorporate with a function call vs a closure) but I’m a little baffled as to why it’s popped up in the standard library, especially with such bizarre and tortured declarations.

The big win of today’s exercise seems to be standardizing on some greppage:

grep func $0 | sed "s/^ *//" | sed "s/.*func //" | grep -v "///" | sort | uniq | open -f

which you can then diff -y, and search for < and >. Today’s keywords appear to be advance, distance, extend, splice on the Beta 5 side (advancedBy and distanceTo are the renamed versions) and appendContentsOf, flatten, and insertContentsOf on Beta 6.

 

Comments are closed.