What are the rules of automatic semicolon insertion in Swift?

In many programming languages with optional semicolons (such as Go, Kotlin, Ruby, Julia) this code does not work properly:

var i = 1
      + 2

Yet this code correctly works in Swift (i becomes 3).

But this code:

var i = 1
       +2

works differently in Swift (i becomes 1).
Why?

It's the same as

var i = 1 + 2

vs.

var i = 1 +2

The latter is treated as a unary plus and therefore 1 +2 is not a valid expression. Because it is not, the compiler assumes the +2 part is a new statement and tries to parse it as such.

3 Likes

I'm not really sure, but every time I hit this error it seems like a bug to me... I mean the compiler should be able to understand this correctly? cc @rintaro

Well the compiler does understand it correctly: in Swift + or - without a following space are treated as unary operations. You can have e.g.

let i = a + -b
1 Like

@crontab is correct: this does not have to do with line breaks at all, but rather that Swift has a rule that binary operators must have either whitespace on both sides or not whitespace on both sides. It simplifies parsing for both machines and humans in a language where custom operators are possible.

12 Likes

Thank you for the clarification @xwu
I wonder if such cases are possible to be detected in order for us to provide better diagnostics. Because the current message is 'consecutive statements must be separated by ;' which may be a bit confusing, so if we could provide something that hints towards this rule for binary operators maybe that could be helpful =]

1 Like

Ok, thanks for clarification.
But what about automatic semicolon insertion in Swift?
Are there any pitfalls, like in JavaScript and some other programming languages?

We were aware of those problems and specifically tried to avoid them in Swift's design, in several ways:

  • Swift is statically typed, so an unexpected joining of statements is quite unlikely to type-check.
  • Swift warns about ignoring the results of (most) expressions that produce non-Void values, so an unexpected splitting of statements is almost certain to be pointed out to the programmer.
  • Swift enforces the spacing rule everywhere, not just when it affects statement splitting; this forces programmers to be consistent about that style, making code that could lead to an unexpected splitting easier to see even without the help of a tool.

Because of all this, Swift's spacing rule is, at least in my opinion, just generally less likely to cause problems than the statement-separation rules used in most other languages. The nature of the rule means that the most likely mistake is that programmers accidentally split a statement by using inconsistent spacing around a binary operator. (It is very uncommon in practice to accidentally add spacing before/after an operator that's meant to be unary. There are also fairly few unary operators in Swift to begin with.) That's almost certain to lead to an immediate warning or error, and the text of that will be specifically about statement composition, not some sort of general "can't pass X to a Y" error that'll take a while to track back to the parsing problem.

I think the biggest downside is that programmers have to type more carefully even in interactive sessions (e.g. in the debugger) where they ordinarily wouldn't care about code style.

10 Likes

Speaking of which, why isn't this an error?

Unfortunately there is a tendency to ignore warnings in some lower quality projects. I've seen some Swift codebases that generate hundreds and even thousands of warnings, completely ignored by the developer(s).

The consequences of ignroing this particular warning can be worse than enforcing the rule "no non-void expressions", like the original question here demonstrates. Then there's @discardableResult and you should never have a problem with this rule if it's enforced in the language.

In general, we aim to make problems warnings when they're soundly implementable and can reasonably occur in partially-written code.

1 Like

I think this should be documented officially, like Implicit line joining in Python and Automatic Semicolon Insertion in JavaScript.

It's in the language reference, in the section titled operators.

I didn't find there anything about statement-separation rules (or automatic semicolon insertion).

It could definitely be clearer. Statement productions end when no further productions are possible, which is determined by whether the next token can be parsed as the appropriate kind of operator. The reference does not call it "automatic semicolon insertion" because, unlike in some languages, that's not the model of what's happening.

7 Likes