I've mentioned this before, but it's still a mystery to me, and I think this little program might present a clearer view of the confusion.
// Two very similar functions:
func foo(a: Int, _ b: Int) { print("foo", a, b) }
func bar(a: (Int, Int)) { print("bar", a.0, a.1) }
// Type aliases for what I guess are the types of foo and bar (and a bonus type Baz):
typealias Foo = (Int, Int) -> Void
typealias Bar = ((Int, Int)) -> Void
typealias Baz = (((Int, Int))) -> Void
// According to the rules of parenthesized expressions and one element tuples (see the Swift book),
// these should all be the same type, which they are, at least according to this:
print(Foo.self == Bar.self) // true
print(Foo.self == Baz.self) // true
// Foo, Bar and Baz are all the same, which makes sense. So the types of foo
// and bar should be the same too, which they are, at least according to this:
print(foo.dynamicType) // (Int, Int) -> ()
print(bar.dynamicType) // (Int, Int) -> ()
print(foo.dynamicType == bar.dynamicType) // true
// And they also seem to be the same when called using this operator:
infix operator § {}
func §<ParamListType, ResultType>(fn: ParamListType -> ResultType, args: ParamListType) -> ResultType {
return fn(args)
}
let x = (1, 2)
foo § (1, 2) // foo 1 2
bar § (1, 2) // bar 1 2
foo § x // foo 1 2
bar § x // bar 1 2
// Everything is clear and easy to understand for me up to this point.
// BUT calling them with the regular function call syntax complicates/confuses things (at least for me):
foo(x) // foo 1 2
bar(x) // bar 1 2
foo(1, 2) // foo 1 2
bar(1, 2) // Error: Extra argument in call (Why? I mean Isn't the type of the argument list here (1, 2), which is the same as eg ((1, 2))?)
foo((1, 2)) // Error: Missing argument for parameter #2 in call (Why? (foo(x) works, why shouldn't it work when x is written as a tuple literal?))
bar((1, 2)) // bar 1 2
// So, foo and bar can / cannot be called in those two ways, but it turns out
// it is really easy to invert their working vs non-working ways of calling:
let fooInBarsClothing: Bar = foo
let barInFoosClothing: Foo = bar
// This will make them behave in the way their names suggests, even
// though we saw above that Bar and Foo are the same type!
fooInBarsClothing(1, 2) // Error (but worked above)
barInFoosClothing(1, 2) // bar 1 2 (but was an error above)
fooInBarsClothing((1, 2)) // foo 1 2 (but was an error above)
barInFoosClothing((1, 2)) // Error (but worked above)
Can anyone explain and / or understand the rules behind this?