Grammar of postfix-self expression

Hi! I've stumbled to grammar of postfix-self expression:

postfix-self-expression β†’ postfix-expression . self

https://docs.swift.org/swift-book/ReferenceManual/Expressions.html#ID401

And it seems very strange to me, how to express something like [Int].self or Int?.self in this grammar?

It looks like it can be done with some hacks, via literals, identifiers and optional-chaining-expression, for example, [Int] is primary -> literal -> array-literal -> expression -> postfix -> primary -> identifier, but that seems really weird.

Isn't the grammar just suppose to have option for type?

postfix-self-expression β†’ type . self

At a glance I'd say I agree with you here, maybe it's a bug/omission from the grammar, since the syntax outline right above it in that section has essentially your example as well.

I think it actually makes sense, though it's a bit obscure.

For historical (Objective-C**) reasons, you can add .self to pretty much any expression, and the resulting value is that same expression's value. In the informal lexical grammar of the document, postfix-expression basically represents the concept of "pretty much any expression".

([Int] is a postfix-expression because it's a primary-expression because it's a literal-expression because it's a literal type name. It isn't an array-literal. A literal array of 1 type would be [Int.self], not [Int].)

In most cases, there's no reason to add .self, but a type name literal alone isn't treated as a value. Adding .self forces it to be treated as a value, so that you can (for example) pass the type as a parameter to a function.


**In Obj-C, KVC always requires an object and a non-empty key-path to access a value. To reference the object itself, you don't have a key-path, so NSObject defined a self method, which works as key-path "self" in KVC. It looks like this works in Swift too:

let myself = self[keyPath: \.self]
3 Likes

Hmm, it still seems like something's missing from the Language Referenceβ€”the allowed productions for literal-expression are:

literal-expression β†’ literal
literal-expression β†’ array-literal | dictionary-literal | playground-literal
literal-expression β†’ #file | #filePath | #line | #column | #function | #dsohandle

and the literal production rule is:

literal β†’ numeric-literal | string-literal | boolean-literal | nil-literal

which doesn't encompass "literal type name" AFAICT. Am I missing something?

The operand of .self doesn't have to be a type. Ambiguities are resolved in favor of a type, though.

Your example is ambiguous: it could also parse as an array literal with a single element that's a reference to the Int type. Since this is also the sugar syntax for Array<Int>, Swift prefers the latter.

So, because grammar needs to be completely unambiguous, and every type is reachable via postfix expression (even though in a weird way), that's why there is no postfix-self-expression β†’ type . self rule?

Yes, I'm not saying that it have to be a type, all I'm saying that it can be a type, and that not represented in grammar.

I've discovered another example: (() -> ()).self, and function-type () -> () is not expressible as postfix expression, or I'm missing something.

That's not correct. There is no such thing as "literal type name" in grammar, there is a type, but that's not literal. Secondly, you can reach [Int].self through array literal, as I tried to show above shortly, but here is full version:

// [Int].self
postfix-self-expression β†’ postfix-expression . self 
// postfix-expression: [Int]
postfix-expression β†’ primary-expression 
// primary-expression: [Int]
primary-expression β†’ literal-expression 
// literal-expression: [Int]
array-literal β†’ [ array-literal-items opt ] 
// array-literal-items: Int
array-literal-items β†’ array-literal-item ,opt | array-literal-item , array-literal-items 
// array-literal-item: Int
array-literal-item β†’ expression 
// expression: Int
expression β†’ try-operator opt prefix-expression binary-expressions opt  
// try-operator: , prefix-expression: Int, binary-expressions: 
prefix-expression β†’ prefix-operator opt postfix-expression
// prefix-operator: , postfix-expression: Int
postfix-expression β†’ primary-expression
// primary-expression: Int
primary-expression β†’ identifier generic-argument-clause opt
// identifier: Int, generic-argument-clause:

Indeed, Int is a valid identifier (identifier grammar is complicated, and can be found here).

1 Like

You're right β€” it's not a literal-expression.

However, I think it's correct to describe it under the primary-expression . self rule and not a (potential) type . self rule.

Something like [Int].self or Int?.self is already shaped like a primary-expression followed by .self, and as @John_McCall said it's reinterpreted as the correct thing by a later compiler decision. These things don't need a new rule.

If the type . self rule existed as you proposed, then something like () -> ().self would be allowed under the rule, since () -> () is a type.

(() -> ()).self works because the parenthesized part is shaped like a primary-expression: it's a binary-expression made primary by the parentheses. Just like the other cases, it's reinterpreted as the correct thing later.

1 Like
Terms of Service

Privacy Policy

Cookie Policy