Basics
See
- A Swift Tour - https://docs.swift.org/swift-book/GuidedTour/GuidedTour.html#//apple_ref/doc/uid/TP40014097-CH2-ID1 
- Getting Started 
- Size, Stride, Alignment 
- Swift And C: Everything You Need to Know on Types, Pointers and more - https://www.uraimo.com/2016/04/07/swift-and-c-everything-you-need-to-know/ 
swift --version
swift-driver version: 1.62.15 Apple Swift version 5.7.2 (swiftlang-5.7.2.135.5 clang-1400.0.29.51)
Target: x86_64-apple-macosx13.0
To start the REPL commandline:
swift repl
./code/1-hello.swift
// swiftc ./1-hello.swift
print("Hello, world!")
// Note:
// 1. It is not println but it still prints a new line
// 2. There is no semicolon
// 3. There is no main(), like Python
swiftc ./1-hello.swift
It will generate an executable ./1-hello.
otool -L ./1-hello
./1-hello:
  /usr/lib/libobjc.A.dylib (compatibility version 1.0.0, current version 228.0.0)
  /usr/lib/libSystem.B.dylib (compatibility version 1.0.0, current version 1319.0.0)
  /usr/lib/swift/libswiftCore.dylib (compatibility version 1.0.0, current version 5.7.1)
ls -lh 1-hello
-rwxr-xr-x  1 fangjun  staff    33K Jan 21 11:55 1-hello
./code/2-variables.swift
var myVariable = 42
myVariable = 50
let myConstant = 43
print("myVariable is \(myVariable)")
print("myConstant is \(myConstant)")
let implicitInteger = 1
let implicitDouble = 1.0
let explicitDouble: Double = 1
let myFloat: Float = 1.2
let label = "The width is "
let width = 100
var widthLabel = label + String(width)
widthLabel = "\(label)\(width)"
print(widthLabel)
// """
let s = """
  abc
  def
  """
// Note: there are leading spaces before the ending """
print(s)
/*
myVariable is 50
myConstant is 43
The width is 100
abc
def
*/
For arrays, see also https://docs.swift.org/swift-book/documentation/the-swift-programming-language/collectiontypes
./code/3-array-dict.swift
var fruits = ["strawberries", "limes", "apples"]
fruits[1] = "grapes"
print(fruits) // ["strawberries", "grapes", "apples"]
precondition(fruits.isEmpty == false)
precondition(fruits.count == 3)
// resized automatically
fruits.append("blueberries")
precondition(fruits.count == 4)
precondition(fruits.first == "strawberries")
precondition(fruits.last == "blueberries")
// assign by copy!
var fruits2 = fruits
fruits2.append("banana")
precondition(fruits.last == "blueberries")
precondition(fruits2.last == "banana")
print(fruits) // ["strawberries", "grapes", "apples", "blueberries"]
print(fruits2) // ["strawberries", "grapes", "apples", "blueberries", "banana"]
var intArray: [Int] = [1, 2, 3]
precondition(intArray.count == 3)
precondition(intArray[0] == 1)
precondition(intArray[1] == 2)
precondition(intArray[2] == 3)
intArray = []
precondition(intArray.isEmpty)
var floatArray = Array(repeating: Float(0), count: 3)
precondition(floatArray.count == 3)
precondition(floatArray[0] == 0)
precondition(floatArray[1] == 0)
precondition(floatArray[2] == 0)
var floatArray2 = Array<Float>(repeating: 0, count: 3)
precondition(floatArray2.count == 3)
precondition(floatArray2[0] == 0)
precondition(floatArray2[1] == 0)
precondition(floatArray2[2] == 0)
var occupations = [
  "Tom": "Captain",
  "Jerry": "Mechanic",
]
print(occupations) // ["Tom": "Captain", "Jerry": "Mechanic"]
occupations["Tom"] = "Teacher"
precondition(occupations["Dan"] == nil) // not exist, so return nil
let emptyArray: [String] = []
let emptyDict: [String: Float] = [:]
./code/4-if.swift
let individualScores = [75, 43, 103, 87, 12]
var teamScore = 0
for score in individualScores {
  if score > 50 {
    teamScore += 3
  } else {
    teamScore += 1
  }
}
// 11
print(teamScore)
var optionalString: String? = "Hello"
// false
print(optionalString == nil)
var optionalName: String? = "Tom"
var greeting = "Hello!"
// if optionalName is nil, then the condition is false
// if optionalName is not nil, then the condition is true and optionalName is unwrapped and assigned to name
if let name = optionalName {
  greeting = "Hello,\(name)"
}
// Hello,Tom
print(greeting)
let nickname: String? = nil
let fullName: String = "Tom Green"
// Hi, Tom Green
let informalGreeting = "Hi, \(nickname ?? fullName)"
// if nickname is not nil, then nickname is used
// if nickname is nil, then fullName is used
print(informalGreeting)
if let nickname {
  print("Hey, \(nickname)")
}
// if can be used as an expression!
let i = 3
let b = if i >= 0 {
    1
} else {
    -1
}
// 1
print(b)
var s: String?  // initialized to nil by default
print(s == nil) // true
./code/5-switch.swift
let vegetable = "red pepper"
switch vegetable {
  case "celery":
    print("celery")
  case "cucumber", "watercress":
    print("cucumber or watercress")
  case let x where x.hasSuffix("pepper"):
    print("x")
  default:
    print("Everything tastes good in soup.")
}
// 1. no need to use break
// 2. default is mandatory so that it is exhaustive
./code/6-for.swift
let interestingNumbers = [
  "Prime": [2, 3, 5, 7, 11, 13],
  "Fibonacci": [1, 1, 2, 3, 5, 8],
  "Square": [1, 4, 9, 16, 25],
]
var largest = 0
for (_, numbers) in interestingNumbers {
  for number in numbers {
    if number > largest {
      largest = number
    }
  }
}
print(largest) // 25
var total = 0
for i in 0..<4 {
  total += i
}
print(total) // 6
total = 0
for i in 0...4 {
  total += i
}
print(total) // 10
./code/7-while.swift
var n = 2
while n < 100 {
  n *= 2;
}
print(n) // 128
var m = 2
repeat {
  m *= 2;
} while (m < 100)
print(m) // 128
./code/8-func.swift
func greet(person: String, day: String) -> String {
  return "Hello \(person), today is \(day)"
}
print(greet(person: "Bob", day: "Tuesday"))
// print(greet("Bob", day: "Tuesday")) // error: missing argument label 'person:' in call
func greet2(_ person: String, on day: String) -> String {
  return "Hello \(person), today is \(day)"
}
// print(greet2(person: "Bob", day: "Tuesday")) // error: incorrect argument labels in call (have 'person:day:', expected '_:on:')
print(greet2("Bob", on: "Tuesday"))
func calculateStatistics(scores: [Int]) -> (min: Int, max: Int, sum: Int) {
  var min = scores[0]
  var max = scores[1]
  var sum = 0
  for score in scores {
    if score > max {
      max = score
    } else if score < min {
      min = score
    }
    sum += score
  }
  return (min, max, sum)
}
let statistics = calculateStatistics(scores: [5, 3, 100, 3, 9])
print(statistics.sum) // 120
print(statistics.2) // 120
func returnFifteen() -> Int {
  var y = 10
  func add() {
    y += 5
  }
  add()
  return y
}
print(returnFifteen()) // 15
func makeIncrementer() -> ((Int) -> Int) {
  func addOne(number: Int) -> Int {
    return number + 1
  }
  return addOne
}
var increment = makeIncrementer()
print(increment(7)) // 8
func hasAnyElement(list: [Int], condition: (Int) -> Bool) -> Bool {
  for item in list {
    if condition(item) {
      return true
    }
  }
  return false
}
func lessThanTen(number: Int) -> Bool {
  return number < 10
}
var numbers = [20, 19, 7, 12]
print(hasAnyElement(list: numbers, condition: lessThanTen)) // true
// the closure has to be put in {}
print(hasAnyElement(list: numbers, condition: {(number: Int) -> Bool in number < 1})) // false
// we can omit the input argument type and return type
print(hasAnyElement(list: numbers, condition: {number in number < 1})) // false
print(numbers.map({ (number: Int) -> Int in
  let result = 3 * number
  return result
})) // [60, 57, 21, 36]
let mappedNumber = numbers.map({number in 3 * number})
print(mappedNumber) // [60, 57, 21, 36]
var sortedNumbers = numbers.sorted {$0 > $1}
print(sortedNumbers) // [20, 19, 12, 7]
sortedNumbers = numbers.sorted {$0 < $1} // also ok
print(sortedNumbers) // [7, 12, 19, 20]
./code/9-class.swift
class Shape {
  var numberOfSides = 0
  func simpleDescription() -> String {
    return "A shape with \(numberOfSides) sides."
  }
}
var shape = Shape()
print(shape.numberOfSides) // 0
shape.numberOfSides = 4
print(shape.numberOfSides) // 4
var simpleDescription = shape.simpleDescription()
print(simpleDescription) // A shape with 4 sides
// with constructor
class NamedShape {
  var numberOfSides = 0
  var name: String
  init(name: String, numberOfSides: Int) {
    self.name = name
    self.numberOfSides = numberOfSides
  }
  func simpleDescription() -> String {
    return "\(name): A shape with \(numberOfSides) sides"
  }
}
var namedShape = NamedShape(name: "Hello", numberOfSides: 10)
print(namedShape.simpleDescription())
class Square: NamedShape {
  var sideLength: Double
  init(sideLength: Double, name: String) {
    self.sideLength = sideLength
    super.init(name: name, numberOfSides: 4)
  }
  func area() -> Double {
    return sideLength * sideLength
  }
  override func simpleDescription() -> String {
    return "A square with side length \(sideLength)"
  }
}
var square = Square(sideLength: 10, name: "MySquare")
print(square.simpleDescription()) // A square with side length 10.0
print(square.area()) // 100.0
// property getter/setter
class EquilateralTriangle: NamedShape {
  var sideLength: Double = 0.0
  init(sideLength: Double, name: String) {
    self.sideLength = sideLength
    super.init(name: name, numberOfSides: 3)
  }
  var perimeter: Double {
    get {
      return 3.0 * sideLength
    }
    set {
      // note: the new value has the implicit name newValue
      sideLength = newValue / 3.0
    }
  }
  override func simpleDescription() -> String {
    return "An equilateral triangle with side of length \(sideLength)."
  }
}
var triangle = EquilateralTriangle(sideLength: 10, name: "MyTriangle")
print(triangle.perimeter) // 30.0
triangle.perimeter = 15
print(triangle.perimeter) // 15.0
print(triangle.sideLength) // 5.0
./code/10-enum.swift
enum Rank: Int {
  case ace = 1
  case two, three, four, five, six, seven, eight, nine, ten
  case jack, queen, king
  func simpleDescription() -> String {
    switch self {
      case .ace:
        return "ace"
      case .jack:
        return "jack"
      case .queen:
        return "queen"
      case .king:
        return "king"
      default:
        return String(self.rawValue)
    }
  }
}
let ace = Rank.ace
let aceRawValue = ace.rawValue
print(ace) // ace
print(aceRawValue) // 1
let two = Rank(rawValue: 2)
print(two ?? "zwei") // two
./code/11-memory-layout.swift
assert(MemoryLayout<Bool>.size == 1)
assert(MemoryLayout<Bool>.stride == 1)
assert(MemoryLayout<Bool>.alignment == 1)
assert(MemoryLayout<Int>.size == 8)
assert(MemoryLayout<Int>.stride == 8)
assert(MemoryLayout<Int>.alignment == 8)
assert(MemoryLayout<Int32>.size == 4)
assert(MemoryLayout<Int32>.stride == 4)
assert(MemoryLayout<Int32>.alignment == 4)
// Like C/C++
struct Example {
  let foo: Int // 8
  let bar: Bool // 1
}
assert(MemoryLayout<Example>.size == 9)
assert(MemoryLayout<Example>.stride == 16)
assert(MemoryLayout<Example>.alignment == 8)
let ex = Example(foo: 10, bar: true)
assert(MemoryLayout.size(ofValue: ex) == 9)
assert(MemoryLayout.stride(ofValue: ex) == 16)
assert(MemoryLayout.alignment(ofValue: ex) == 8)
struct Example2 {
  let bar: Bool // 1
  let foo: Int // 8
}
assert(MemoryLayout<Example2>.size == 16)
assert(MemoryLayout<Example2>.stride == 16)
assert(MemoryLayout<Example2>.alignment == 8)
./code/12-weak-reference.swift
class Author {
  let name: String
  // weak reference is required
  weak var post: Post?
  init(name: String) {self.name = name}
  deinit {print("Author deinit")}
}
class Post {
  let title: String
  var author: Author?
  init(title: String) {self.title = title}
  deinit {print("Post deinit")}
}
var author: Author? = Author(name: "John Snow")
var post: Post? = Post(title: "foo bar")
post?.author = author
author?.post = post
print(author?.post) // Optional(main.Post)
post = nil // Post deinit
print(author?.post) // nil
author = nil // Author deinit
./code/13-pointers.swift
// Unsafe[Mutable][Raw][Buffer]Pointer[Type]
//
// Mutable: means you can change the value
// Raw: means it points to a blob of bytes
// Buffer: means it works like a collection
// Type: means generic typed pointers
//
// UnsafePointer<T>
// UnsafeMutablePointer<T>
//
// UnsafeRawPointer
// UnsafeMutableRawPointer
//
// UnsafeRawBufferPointer
// UnsafeMutableRawBufferPointer
//
// UnsafeBufferPointer<T>
// UnsafeMutableBufferPointer<T>
let count = 2
let stride = MemoryLayout<Int>.stride
let alignment = MemoryLayout<Int>.alignment
let byteCount = count * stride
let pointer = UnsafeMutableRawPointer.allocate(byteCount: byteCount, alignment: alignment)
defer {
  pointer.deallocate()
}
pointer.storeBytes(of: 30, as: Int.self)
pointer.advanced(by: stride).storeBytes(of: 3, as: Int.self)
assert(pointer.load(as: Int.self) == 30)
assert(pointer.load(fromByteOffset: stride, as: Int.self) == 3)
assert(pointer.advanced(by: stride).load(as: Int.self) == 3)
let bufferPointer = UnsafeRawBufferPointer(start: pointer, count: byteCount)
for (index, byte) in bufferPointer.enumerated() {
  print("byte \(index) -> \(byte)")
}
/*
byte 0 -> 30
byte 1 -> 0
byte 2 -> 0
byte 3 -> 0
byte 4 -> 0
byte 5 -> 0
byte 6 -> 0
byte 7 -> 0
byte 8 -> 3
byte 9 -> 0
byte 10 -> 0
byte 11 -> 0
byte 12 -> 0
byte 13 -> 0
byte 14 -> 0
byte 15 -> 0
*/
./code/14-typed-pointers.swift
let count = 2
let stride = MemoryLayout<Int>.stride
let pointer = UnsafeMutablePointer<Int>.allocate(capacity: count)
pointer.initialize(repeating: 0, count: count)
defer {
  pointer.deinitialize(count: count)
  pointer.deallocate()
}
pointer.pointee = 42
pointer.advanced(by: 1).pointee = 6
let bufferPointer = UnsafeBufferPointer(start: pointer, count: count)
for (index, value) in bufferPointer.enumerated() {
  print("value \(index) -> \(value)")
}
/*
value 0 -> 42
value 1 -> 6
*/
./code/15-async.swift
import Foundation // for sleep
func fetchUserID(from server: String) async -> Int {
    let tid =  pthread_self()
    print("fetch userID from \(server) with thread ID \(tid)")
    if server == "primary" {
        return 97
    }
    return 501
}
func fetchUserName(from server: String) async -> String {
    print("fetch userName from \(server) with thread ID \(pthread_self())")
    let userID = await fetchUserID(from: server)
    print("after await fetch userName from \(server) with thread ID \(pthread_self()), user id \(userID)")
    if userID == 501 {
        return "John Appleseed"
    }
    return "Guest"
}
func connectUser(to server: String) async {
    print("here0")
    async let userID = fetchUserID(from: server)
    print("here1")
    async let userName = fetchUserName(from: server)
    print("here2")
    let greeting = await "Hello \(userName), user ID \(userID)"
    print(greeting)
}
if false {
    Task {
        await connectUser(to: "primary")
    }
    sleep(1)
}
if true {
    let userIDs = await withTaskGroup(of: Int.self) { group in
        for server in ["primary", "secondary", "development"] {
            group.addTask {
                return await fetchUserID(from: server)
            }
        }
        var results: [Int] = []
        // for await returns result in completion order, not in adding order
        for await result in group {
            results.append(result)
        }
        return results
    }
    print(userIDs)
}
if true {
    let userNames = await withTaskGroup(of: String.self) { group in
        for server in ["primary", "secondary", "development"] {
            group.addTask {
                return await fetchUserName(from: server)
            }
        }
        var results: [String] = []
        for await result in group {
            results.append(result)
        }
        return results
    }
    print(userNames)
}