Pointer Explanation
What’s happening here is you’re hitting an implicit conversion of arrays to pointers, that is there for C compatibility purposes.
Ordinarily, you wouldn’t be able to add 1
to an array. I mean, what would it mean to do that? However, Swift does have an implicit conversion of arrays to pointers, so that you can pass arrays into C functions:
import Darwin
// prints out “hello” using a standard C function that takes a char*
puts([104,101,108,108,111,0])
And you can add integers to pointers (to do good ol’ pointer arithmetic):
// x will be an UnsafePointer<Int>
let x = [1,2,3] + 1
Now, to stop you doing this by accident, this is only supposed to work on literals:
let a = [104,101,108,108,111,0]
// error: binary operator '+' cannot be applied to operands of type '[Int]' and 'Int'
let x = a + 1
But when using generic functions, this conversion still happens (possibly unintentionally).
Issues with your Map
It looks from your definition like you’re trying to write a version of map
for optionals – that is, something that takes an optional, and maps the contents if it has some.
But then, instead of mapping optionals, you’re using it to on sequences. In fact in your code snippet, on the line let test2 = map(test1, { $0 + 1 })
, you aren’t calling your map
at all – you’re calling the standard library version that takes a sequence (and returns an array). Try putting an assert(false)
in there – you’ll see it’s not being called the first time around.
Map for optionals and map for arrays are very conceptually similar. This is because optionals and arrays are both “functors” – the name for things that can be “mapped over”. Think of them both as containers – types that contain other types. In the case of optionals, they contain a value or not. In the case of arrays, they contain any number of values. But in both cases, it’s useful to have a function that you apply to the “contents” while leaving them within the “container”.
Consider the following code. It has two maps, for sequences and optionals, and applys them in turn. The last example seems to be what you were looking for in your question’s last case – mapping plus-one on each member of an array of optionals. This is really two maps, one within the other.
func mymap<A, B>(x: A?, transform: A -> B) -> B? {
println("map for optionals called!")
if let x1 = x {
return transform(x1)
}
return nil
}
func mymap<S: SequenceType, T>(source: S, transform: S.Generator.Element -> T) -> [T] {
println("map for sequences called!")
var result: [T] = []
for x in source {
result.append(transform(x))
}
return result
}
let test1 = [1, 2, 3, 4]
// prints "map for sequences called!"
let test2 = mymap(test1, { $0 + 1 })
println(test2) // prints
let test3: Int? = 5
// prints "map for optionals called!"
let test4 = mymap(test3, { $0 + 1 })
println(test4) // Optional(6)
let test5: [Int?] = [1, nil, 3, 4]
// prints "sequences called" followed by 4 "optionals called"
let test6 = mymap(test5) { mymap($0) { i in i + 1 } }
println(test6) // [Optional(2), nil, Optional(4), Optional(5)]