[swift-evolution] Making `.self` After `Type` Optional

Joe Groff jgroff at apple.com
Wed Mar 9 16:57:19 CST 2016


> On Mar 9, 2016, at 2:28 PM, Dave Abrahams via swift-evolution <swift-evolution at swift.org> wrote:
> 
> 
> on Wed Mar 09 2016, Brent Royal-Gordon <swift-evolution at swift.org> wrote:
> 
>>> I would like to propose making `.self` After a Type optional when referencing Types in expressions.
>> 
>>> This has been confirmed as a bug, and the report can be seen here <https://bugs.swift.org/browse/SR-899>.
>>> 
>>> After a Twitter conversation with Joe Groff on the Swift team
>>> (https://twitter.com/jckarter/status/707287663586324481) it is
>>> determined that this requirement is due to difficulty disambiguating
>>> generics `Foo<T>` vs infix less-than operations `Foo < T`.
>> 
>> My understanding from previous Twitter discussions is that the primary
>> reason for this feature is to keep you from writing `Foo` where you
>> meant `Foo()`. That is, it's a deliberate design, meant to keep you
>> from making mistakes. I suspect that you will have to overcome *that*
>> impulse, not just any narrow parsing issue.
> 
> That is correct.  Before 1.0, Swift used to work without ".self"; we
> started requiring ".self" because one of the Swift designers
> with experience in other languages that didn't require ".self" said that
> it was a persistent source of confusion for users.
> 
> Personally, I've always disliked what ".self" did to my source code, but I
> have no basis on which to argue with that other designer's experience.

As the designer in question, I've come around to this as well; our type system is sufficiently stronger than that other language that I think the consequences of accidentally typing `let x = Int` when you meant `let x = Int()` are far easier to understand. However, `.self` is also a bit of load-bearing duct-tape that currently supports some other parsing aspects of Swift's syntax. We have a bunch of type sugar syntax that's overloaded with expression syntax, such as Int?, [Int], [String: Int], and (String, Int); we currently handle this by special-casing the sugar forms when they appear as the LHS of a member lookup or function call. We could address that problem by treating it more like an overload resolution problem, and say that applying `[]`, `[:]`, `?`, or `(,)` to type references always favors building a type reference over forming an array/dictionary/optional/tuple. There's also the lower-level parsing problem with generic parameter brackets that Tanner mentioned in his leading email. We stole the same trick that C# uses to disambiguate `Foo<T, U>(x)` from `(Foo < T), (U > (x))` without relying on name lookup; we assume that a type reference in an expression is always the root of a member lookup or constructor call, and that 'x > (y)' is sufficiently unlikely given the low relative precedence of >, that we can look ahead after we see a '<' to find a '>.' or '>(' token pair and favor the parse as a generic parameter list in those cases. If we're going to break the invariant that type references in expressions are always followed by a member lookup or constructor call, we'll need an alternative disambiguation scheme.

-Joe


More information about the swift-evolution mailing list