There is so much weird here that comes of tuples being like an HList type and not a type product.
The name unit to me implies the unit of the type product operation, which is how the ML family including Haskell uses it. (x, y) : T1 * T2. And maybe you write that type as (T1, T2) if you want. A tuple of one type isn’t a thing because it’s just the type, and the product of a type with unit is the identity. T * () = T = () * T. The type product is associative. T1 * (T2 * T3) = (T1 * T2) * T3. There are usually syntactic features making it different structurally which you need for stuff to make sense with opaque types, but… significantly, you never need a tuple of a single type in this model to be different from the type itself.
But here in Scala tuples aren’t type products, they’re heterogenous lists. This is very useful for being able to analyze and synthesize types with them. So that cat is out of the bag. *: isn’t a type product, it isn’t associative. () isn’t a unit type even if we call it that because we don’t actually have an operator for it to be a unit. A list of one item does need to be different from a single item, and here we are.
Anyway… I felt I should say something because I think this impedance mismatch is part of the frustration and confusion and misunderstanding here.
(And it’s all exacerbated because for a lot of people their first introduction to the term is Python’s “tuple” which has nothing to do with any of this and instead just means “immutable list”.)
I have made an unfortunate discovery while drafting a SIP for this feature:
val a = (
1,
)
a // 1: Int
Trailing commas only apply on multiline parameter lists, which explains why (1,2,) doesn’t work, but the following does and desugars to (1,2):
(
1,
2,
)
However this seems to have been generalized to singleton tuples where (\n1,\n) is seen as equivalent to (1) itself equivalent to just 1 !
(This is also present in both the current Scala 3 Next and latest Scala 2)
This can be traced to the original implementation:
Where skipping the comma is done in the Scanner, so even before the Parser knows if this is a parameter list or a tuple !
(Of course in the former this is not an issue since f(1,) would be equivalent to f(1))
However the corresponding SIP does not mention this, only focussing on parameter list
The PR description does extend it to notably tuples, but again no mention of this edge-case is done
As such, I am not sure whether this is a bug or not ?
This question matters because if this is not a bug, the feature does affect previously valid code (and not invalid-but-the-compiler-thinks-it’s-fine)
It also has the benefit of removing the need for autotupling:
f(a, b) // f is passed two parameters: a and b
f((a, b)) // f is passed one parameter: Tuple2(a, b)
I am worried for the interactions between such a syntax and people with sight or reading issues such as blurry vision or dyslexia
If this syntax would make it hard for you to read code, please let us know