Smeegol
Smeegol

Reputation: 2098

Why guard let self = self else { return } can be compiled successfully

Question 1: in guard let self = self else { return }, first self and second self are same, why it can be compiled successfully? Because normal let self = self will be compiled with errors.

Question 2: Even I found guard let self else { return } in some projects, why it can be compiled successfully?

Upvotes: -2

Views: 130

Answers (2)

Rob
Rob

Reputation: 438152

The guard let is an “optional binding” pattern. It is like the if let optional binding discussed in The Swift Programming Language: Optional Binding, except that guard let affords an “early exit”. Consider:

guard let self else {
    // if `self` was `nil`, then just exit
    return
}

// otherwise, if we got here, then `self` was not `nil`, and it is
// no longer an optional from this point on

This is a variation of the if let optional binding pattern discussed in The Swift Programming Language. For example:

if let self {
    // you will only get here if `self` was not `nil`;
    // inside this block, `self` is longer an optional
    …
}

// but that optional binding only applies within the block above; once you 
// get here, you’re dealing with an optional reference to `self` again

You contrasted that with a simple let self = self, which performs no optional binding: That will undoubted generate compilation errors regarding the misuse of the reserved keyword, self, as well as any subsequent code that was expecting self to no longer be an optional. You can only use self like this from within an optional binding pattern, such as the if let or guard let patterns shown above (or while let, which is less common).


A few links for your reference, discussing the evolution of the syntax associated with optional binding of self:

  1. SE-0079 discusses the use of if let self = self {…} pattern:

    The proposed solution entails allowing self to be upgraded from a weak reference to a strong reference using optional binding.

    That proposal replaces the legacy pattern of …

    if let strongSelf = self { … }
    

    … with something that avoids the confusion of introducing a separate variable name, reducing it to:

    if let self = self { … }
    

    That was introduced in Swift 4.2.

  2. The shortening of this syntax is contemplated in SE-0345, which says:

    Optional binding using if let foo = foo { … }, to create an unwrapped variable that shadows an existing optional variable, is an extremely common pattern. This pattern requires the author to repeat the referenced identifier twice, which can cause these optional binding conditions to be verbose, especially when using lengthy variable names. We should introduce a shorthand syntax for optional binding when shadowing an existing variable:

    let foo: Foo? = …
    
    if let foo {
        // `foo` is of type `Foo`
    }
    

    The pattern works for self, too. Thus, the example in my first point is reduced to:

    if let self { … }
    

    That was introduced in Swift 5.7.

  3. As an aside, SE-0365, in its discussion of “implicit self”, shows lots of examples of the if let and guard let patterns, e.g.:

    guard let self else { … }
    

Upvotes: 2

lazarevzubov
lazarevzubov

Reputation: 2315

By writing let self = self you declare a variable self and give it a value of self (i.e., a reference to the instance of the object that the line is called inside).

Swift allows variable shadowing, so it's legal to create a local variable self that shadows the identifier self from the outer scope.

There's one caveat, though: self is also a special word in Swift and can't be used as a variable name (the compiler emits the error "Keyword 'self' cannot be used as an identifier here")... unless you apply an escaping technique: let `self` = self.

On the other hand, guard doesn't require this kind of escaping. I suppose that since the idiom guard let self = self is so common, language developers decided to make an exception for it to avoid some boilerplate code.

In later versions of the language, they also introduced a shorthand syntax for unwrapping optional values: guard let self. In fact you can use it with any optional variable to unwrap it: guard let anyOptional.

As for why guard let self else { return } cannot be compiled in some places, it's impossible to say without more details, but I have two assumptions:

  1. The project might be compiled with a language version earlier than the shorthand syntax was introduced in, therefore the syntax is considered invalid.
  2. self itself might be unavailable in the context (i.e., the code is written outside of an instance of an object, e.g., in the global scope).

Upvotes: 0

Related Questions