Polyglot
Languages Swift syntax
Swift § syntax

Syntax

Swift’s syntax is clean and concise — type inference admits omitting most type annotations, semicolons are not required (they may appear only when separating multiple statements on one line), parentheses around if and while conditions are not required (and conventionally omitted), and the convention favours expression-orientation where it admits substantial conciseness. The compiler enforces type safety — the type system catches substantial classes of errors at compile time. Swift admits trailing closure syntax (a hallmark of the language: closures may follow the call’s argument list rather than appearing inside the parentheses), and the let vs var distinction (immutable vs mutable bindings). The combination — concise syntax, type inference, mandatory braces, the conventional discipline favouring let — is the substance of Swift’s syntactic identity.

This page covers the surface a working programmer encounters routinely.

A complete program

The classical hello world:

print("Hello, world!")

A more substantial example:

import Foundation

struct Person {
    let name: String
    let age: Int

    func greeting() -> String {
        "Hello, \(name)."
    }
}

let url = URL(fileURLWithPath: "people.json")
let data = try Data(contentsOf: url)
let people = try JSONDecoder().decode([Person].self, from: data)

for person in people.sorted(by: { $0.age < $1.age }) {
    print(person.greeting())
}

The principal features visible:

  • import Foundation — module import.
  • struct Person { ... } — value-type declaration.
  • let name: String — immutable property.
  • func greeting() -> String — function with return type.
  • "Hello, \(name)." — string interpolation.
  • try Data(contentsOf:) — labelled argument.
  • [Person].self — type-as-value (metatype).
  • { $0.age < $1.age } — closure with shorthand parameter names.
  • for person in ... — iteration.

Compilation and execution:

swiftc hello.swift -o hello && ./hello

# Or interpreted:
swift hello.swift

For project-style work, the Swift Package Manager:

swift package init --type executable
swift run

Source character set

Swift source is interpreted as UTF-8. Identifiers may use Unicode letters; ASCII identifiers are conventional in code, though Unicode is admitted for variable names (and even emojilet 🐶 = "dog").

Identifiers and naming conventions

The conventional Swift naming follows the Swift API Design Guidelines:

FormUseExample
lowerCamelCasevariables, parameters, methods, propertiesuserName, toString()
UpperCamelCasetypes, protocols, generic parametersPerson, Comparable, T
lowerCamelCaseenum cases (since Swift 3)case running, case .pending
UPPER_SNAKE_CASErare; use lowerCamelCase for let constants too

The convention is enforced by community consensus (not by the language) — the Swift Standard Library and Apple’s frameworks follow it strictly. The conventional contemporary Swift is the Swift API Design Guidelines style.

Reserved keywords

The reserved keywords:

associatedtype  class       deinit          enum            extension
fileprivate     func        import          init            inout
internal        let         open            operator        private
protocol        public      rethrows        static          struct
subscript       typealias   var

break           case        continue        default         defer
do              else        fallthrough     for             guard
if              in          repeat          return          switch
where           while

as              Any         catch           false           is
nil             super       self            Self            throw
throws          true        try

_                                                            // wildcard

There are also contextual keywords that are reserved only in specific positions: actor, async, await, convenience, dynamic, final, lazy, mutating, nonisolated, optional, override, prefix, postfix, required, some, weak, unowned, etc.

For using a reserved word as an identifier, the backtick form:

let `class` = "Math 101"                          // class is reserved

The form is admitted but conventionally avoided.

Comments

Two comment forms:

// A single-line comment, terminated by the end of the line.

/* A block comment.
   Block comments admit nesting:
   /* nested comment */
*/

The block-comment form’s nesting (since the original language) is rare among C-family languages — admits substantial commenting-out without breaking on inner block comments.

For documentation comments, the /// and /** */ forms admit Markdown:

/// Greets the named person.
///
/// - Parameter name: The name to greet.
/// - Returns: A greeting string.
func greet(name: String) -> String {
    "Hello, \(name)."
}

/**
 A more substantial documentation comment.

 Admits Markdown formatting and multiple paragraphs.
 */

The conventional Swift documentation tooling (Xcode’s Quick Help, DocC) consumes these comments to produce structured documentation.

Statement terminators

Newlines terminate statements; semicolons admit multiple statements on one line:

let x = 5
let y = 10
let z = x + y

// Equivalent:
let x = 5; let y = 10; let z = x + y

The conventional discipline:

  • One statement per line — newlines terminate.
  • Semicolons rarely used — only for compactness on one line.

Variable declarations

Two principal forms:

let x = 5                                          // immutable (preferred)
var y = 10                                         // mutable

let name: String = "Alice"                         // explicit type
let name = "Alice"                                 // type inferred as String

var age: Int = 30
var age = 30                                       // type inferred as Int

The conventional discipline:

  • Use let by default — the compiler warns on var that is never reassigned.
  • Use var when reassignment is required.
  • Type inference — let the compiler determine the type when the initialiser is unambiguous.

Type annotations

Type annotations follow the colon convention:

let name: String = "Alice"
let age: Int = 30
let pi: Double = 3.14159
let isActive: Bool = true

var values: [Int] = [1, 2, 3]                      // array of Int
var lookup: [String: Int] = [:]                    // dictionary

func add(a: Int, b: Int) -> Int {
    a + b
}

The Swift type system is strict — implicit conversions are not admitted (e.g., Int is not implicitly convertible to Double):

let n: Int = 5
let f: Double = n                                  // ERROR
let f: Double = Double(n)                          // OK

The strictness eliminates a substantial class of conversion bugs.

Functions

The func keyword introduces a function:

func add(_ a: Int, _ b: Int) -> Int {
    a + b
}

func greet(name: String) -> String {
    "Hello, \(name)"
}

func performAction() {                             // no return value (Void)
    print("acting")
}

Swift functions admit parameter labels — distinct from the parameter names. By default, the parameter name is its label:

func send(message: String, to recipient: String) {
    print("sending \(message) to \(recipient)")
}

send(message: "hi", to: "Alice")                   // labels visible at call site

// The _ wildcard suppresses the label:
func add(_ a: Int, _ b: Int) -> Int { a + b }
add(3, 4)                                          // no labels needed

Treated in Functions and closures.

Block syntax

All control-flow constructs require braces — no single-statement form:

if condition {
    doSomething()
}

if condition { doSomething() }                    // OK; one-liner

if condition
    doSomething()                                  // ERROR

The braces are required; the discipline eliminates the dangling-else ambiguity and produces consistent formatting.

The parentheses around if and while conditions are not required (and conventionally omitted):

if x > 0 {                                         // no parens
    print("positive")
}

while !done {                                      // no parens
    advance()
}

String interpolation

Double-quoted strings admit \(expression) for interpolation:

let name = "Alice"
let greeting = "Hello, \(name)!"

let total = 42
let formatted = "Total: \(total) items at $\(price * Double(total))"

The mechanism admits substantial conciseness for formatted strings; treated in Strings.

Trailing closure syntax

A trailing closure — a closure passed as the last argument may appear outside the parentheses:

[1, 2, 3].map({ n in n * 2 })                     // closure inside parens
[1, 2, 3].map { n in n * 2 }                      // trailing closure
[1, 2, 3].map { $0 * 2 }                          // shorthand parameters

// With multiple trailing closures (Swift 5.3+):
UIView.animate(
    withDuration: 0.5,
    animations: { /* ... */ }
) {
    // completion handler
}

The mechanism admits substantial DSL-style syntax (SwiftUI, Combine, etc.).

Optionals

Swift’s distinctive nullability mechanism: optionals — types that may contain nil:

var name: String?                                  // optional; may be nil
name = "Alice"
name = nil                                         // OK

let name: String = "Alice"                         // non-optional; cannot be nil
let name: String = nil                             // ERROR

// Unwrapping:
if let unwrapped = name {                          // optional binding
    print(unwrapped)                               // unwrapped is String, not String?
}

let length = name?.count                           // optional chaining (returns Int?)
let length = name!.count                           // force unwrap (crashes if nil)
let length = name ?? "default"                     // nil-coalescing

Treated in Optionals.

Type-as-value

Swift admits referring to a type as a value via .self:

let stringType = String.self
let arrayType = [Int].self
let optionalType = Int?.self

print(type(of: 42))                                // Int
print(type(of: "hello"))                           // String

The mechanism is conventional in generic functions and JSONDecoder.decode(_:from:) patterns.

Modules and imports

Each Swift project produces a module — a unit of code distribution:

import Foundation                                  // import a system module
import MyLibrary                                   // import a third-party module
import struct MyLibrary.Person                     // import a specific type

Within a module, all files share a common namespace; access between modules is controlled by access control modifiers (public, internal, etc.).

Treated in Scope and modules.

A note on what Swift admits

Several distinguishing features:

  • Optionals — explicit nullability via Optional<T> (treated separately).
  • Value types as default — structs are conventional; classes for reference semantics.
  • Protocols and POP — protocols with default implementations.
  • Generics with constraints — substantial type-system surface.
  • Pattern matching — switch with exhaustive checking.
  • Type inference — admits omitting most annotations.
  • Structured concurrency — async/await, actors, structured task groups.
  • ARC — Automatic Reference Counting for memory management.
  • Property wrappers — declarative attribute extension (@State, @Published).
  • Result builders — DSL syntax (SwiftUI’s view-tree DSL).
  • Codable — automatic serialisation/deserialisation.

A note on what is not in Swift

  • No null pointer dereferences — Optionals encode absence at the type level.
  • No undefined behaviour in safe Swift — overflow checking, bounds checking.
  • No implicit conversionsInt to Double requires explicit conversion.
  • No raw pointers in safe Swift — UnsafePointer admitted but explicitly named.
  • No multiple inheritance — class single inheritance plus protocol composition.
  • No exceptions in the C++ sensethrows is a typed mechanism.
  • No GC — ARC is deterministic.
  • No header files — single source file per type.
  • No preprocessor — but #if, #available are admitted.

The combination — Swift’s particular blend of safety, performance, expressiveness, and Apple ecosystem integration — is the substance of the language’s identity. The discipline produces concise, readable, type-safe code with substantial compile-time guarantees.