Should either, both or none of these two lines compile?

Let's call the two lines mentioned in the title A and B here:

func f(x: Int, _ y: Int) { print(x + y) }
let aTuple = (1, 2)
f(aTuple) // A
f((1, 2)) // B


f(1, 2) should and does obviously compile, but

should A compile?

should B compile?


Details:


In current Swift (Xcode 7.1 beta 3) one of them compiles and the other fails, which I find impossible to wrap my head around.

So I guess this is a (well known) bug, but I filed 23059991 anyway.


I think both A and B should compile, rather than both being errors. And my unconsidered reasoning/feelings behind this has to do with simplicity/elegancy/flexibility/power related to parameter list types, tuples, function/method calling, etc.


This is an example of a very basic part of the language that is (still!) abstruse rather than clear. If it wasn't for things like this, Swift would be great and we would be very productive and happy using it.

should A compile?

I would not expect it to compile. The function parameter list is Int, Int, not (Int, Int)


should B compile?

Same here


This is my current understanding based on the sparse information Apple provided in the old forum and on my cursory reading of the documentation. I understand that some other people believe both A and B should compile.


That said, there are inconsistencies and I suspect that the philosophy within the Swift team changed since 1.0, but it was not reflected consitently in the compiler. I think it is time for Apple to chime in and clarify.

The reason for why the argument list ((1, 2)) is the same as (1, 2) is clear as long as argument lists follows the above quoted rules of tuple patterns and tuple types.


For me, the "reusable tuple concept" was one of the things that stood out as great in my first impression of Swift. It's useful in many ways, for example: it allows us to pass around argument lists as values and call functions with them, and we can make protocols that have the types of various parameter lists as associated types etc. It would cripple the language to remove/complicate rather than correct/simplify/unify/embrace this concept.

I agree that it would be great to hear something from the Swift team.

Btw, do you think that they have deliberately implemented these errors too:

typealias PairOfInts = (Int, Int)

typealias OptionalPairOfIntsA = Optional<(Int, Int)>
typealias OptionalPairOfIntsB = Optional<PairOfInts>

let p = (1, 2)
let a1 = OptionalPairOfIntsA(p) // OK
let b1 = OptionalPairOfIntsB(p) // OK

let a2 = OptionalPairOfIntsA(1, 2) // OK
let b2 = OptionalPairOfIntsB(1, 2) // Error

let a3 = OptionalPairOfIntsA((1, 2)) // Error
let b3 = OptionalPairOfIntsB((1, 2)) // OK

?

I don't mind the disagreement in terms, but “single element” tuples are so different from all the other lengths of tuples, including zero-length as you mention, that they might as well not exist. They can't be nested, labelled, etc. Reminds me of when people were suggesting that “double optionals” should be collapsed to single optionals, which would completely break the type system if you work through examples. Tuples seem similarly broken, but people generally aren't using them for anything much more complex than multiple returns, zipped iterators, etc, so it isn't as noticeable.

I think the current inconsistencies are breaking the system. I would certainly not want "double optionals" to magically collapse into single optionals. So I'm not sure what you mean by that comparison.


Also, I wouldn't write all this if these inconsistencies were not noticable and stopped me from being able to write various very useful/practical/productive high level abstractions.


These inconsistencies makes me less productive and my code unnecessary complicated, full of work-arounds and special casing.


I will not continue arguing after this post, as I think my point is so obvious that it shouldn't need this much justification/motivation.

So I'll conclude by essentially repeating myself (again):


The unifying concept of tuples and parenthesized expressions in Swift is something obviously great.

- It is clearly visible in the grammar of the language (which also becomes simpler because of it).

- It unifies otherwise unnecessarily disparate concepts by being resused for things like: switch, conditional, assignments, associated values, function parameter-types and return-types, (pattern matching) etc.

- People new to the language only have to learn the rules of this concept instead of learning a whole bunch of unneccesarily unrelated concepts.

- When people have learned this concept and sees how it's reused in the language, they will discover how powerful it is and find new similarly powerful ways of reusing it in their own code constructs.


Preferring inconsistency over consistency here just because "people in general (beginners?) are probably not using this for anything much more complex than multiple returns, zipped iterators, etc" suggest a design philosophy that has taken "worse is better" to a whole new level.


The same design philosophy would probably reject eg first class functions, since people in general would probably not be using functions for anything much more complex than calling them directly.


Simple practical benefits of having this implemented in a consistent way:

- Being able to (successfully) treat parameter lists as types (what's called parameter-types in the Swift book and language grammar).

- Being able to (successfully) treat argument lists as values.

- Being able to (successfully) write protocols with associated types for the parameter type of eg an initializer.

- Being able to (successfully) write generic types that conforms to protocols of the kind mentioned above.

- And more ...


In short, again:

Inconsistency in this and many other areas ⇒ less expressive more complicated language.

Consistency in this and many other areas ⇒ more expressive less complicated language.


Note that I included the reference to "worse is better" to indicate that I'm aware of where this discussion might easily end up.

Yes in the usual: Swift is not supposed to be a functional language...

As usual: ?

I think you should read what I've said in this thread much more carefully if you think there is a disagreement or an argument here, so I'll ignore the rest of your post. I was saying that automatically unwrapping single-element tuples causes similar issues to the previously-proposed (note: not by you) idea of automatically unwrapping multiple levels of optionality. I completely agree that all this tuple special-casing (mostly unwrapping single-element tuples and wrapping some things that look like argument lists into tuple arguments) is leading to inconsistencies and absurdities. I would prefer for this to all be rationalised in some way, but I'm not sure which way is best. Some of your posts on this issue have essentially proposed keeping the single-element tuple unwrapping - or at least considering ((T)) a subtype of (T), which is in turn a subtype of T, when calling functions. This would probably work fine if some of the other special cases were removed, but I haven't worked through it.

Right, I see now that you weren't disagreeing, wasn't sure before (I blame english not being my native language), sorry about that.


I guess we can only look forward to a future beta where these inconsistencies have been removed, NOT by removing the unifying tuple / parenthesized expression concept of course!


Until then I'll have to carry on using only the currently non-broken subset of Swift to write depressingly abstractionless code, frustrated by how much better it would have been if only this and that had not been broken. And for every new beta I'll probably not be able to resist wasting time on trying to figure out what exactly constitutes the new currently non-broken subset of Swift ...

But then again I actually prefer the non-broken subset of Swift over ObjC and C or C++ so perhaps I shouldn't complain.

No problem. I presume that if or when we get the ability to destructure tuples in a way that isn't providing overloads for every possible tuple length then some of these issues will have to be addressed, because the family of strange examples you will be able to generate will be a lot larger.

Should either, both or none of these two lines compile?
 
 
Q