As a software engineer who's spent a lot of time working with JavaScript and TypeScript, jumping into Swift feels like a mix of the familiar and the new. Swift's strong type system, combined with its emphasis on safety and performance, can be a bit of a paradigm shift.
In this post, I’ll break down key Swift concepts such as strings, operators, constants, and numbers, while drawing comparisons to JavaScript.
Constants: Embracing Immutability
In JavaScript, constants are declared using const
:
const pi = 3.14;
Similarly, Swift has let
for declaring immutable variables:
let pi = 3.14
Once declared, you cannot reassign pi
, which is exactly how JavaScript constants behave. However, Swift goes a step further: let
applies not only to simple types like numbers or strings but also to complex types like arrays and dictionaries. Once you declare a collection with let
, you can’t change the collection itself (i.e., reassign it), but you can still modify its contents:
let shoppingList = ["Eggs", "Milk"]
// shoppingList = [] // Error: Cannot reassign 'shoppingList'
shoppingList.append("Bread") // This is allowed
This distinction is the same as in JavaScript — const
protects the reference, not the contents of objects or arrays.
Variables: Mutability with var
When you need to create a variable whose value changes, you use var
in Swift, which is equivalent to let
in JavaScript or var
in older versions of JS:
var counter = 5
counter += 1 // 6
This is similar to mutable variables in JavaScript:
let counter = 5;
counter += 1; // 6
Numbers and Type Safety
JavaScript has a single number
type for all numeric values (whether integer, float, etc.). In Swift, numbers are more strictly typed. Swift has multiple numeric types such as Int
, Double
, and Float
to distinguish between different kinds of numbers:
let wholeNumber: Int = 10
let decimalNumber: Double = 3.14
The biggest difference here is that Swift enforces type safety, meaning it won’t let you mix and match different number types without explicit conversion. This is different from JavaScript, where you can freely perform arithmetic between integers and floats:
let result = 5 + 3.14; // Allowed in JavaScript
In Swift, you would need to convert the types manually:
let result = Double(5) + 3.14 // Must convert Int to Double
Strings: Value Types and Copy Semantics
Like JavaScript, strings in Swift are immutable. However, Swift treats strings as value types, meaning each assignment or pass creates a copy rather than a reference:
var greeting = "Hello"
var anotherGreeting = greeting
anotherGreeting = "Hi"
// `greeting` is still "Hello"
In JavaScript, strings are also immutable, but they are passed by reference:
let greeting = "Hello";
let anotherGreeting = greeting;
anotherGreeting = "Hi";
// `greeting` would still be "Hello" due to immutability,
// but it's reference-based rather than copy-based.
Multiline Strings: Flexibility and Readability
Swift provides a quick method of handling multiline strings by using triple quotes ("""
). This feature enhances the readability when dealing with longer blocks of text. Unlike JavaScript, which requires concatenation or backticks for multiline strings, Swift’s approach is more elegant:
let multilineString = """
This is a multiline
string in Swift.
You can write across multiple lines easily.
"""
In JavaScript, you would use template literals with backticks to achieve a similar result:
const multilineString = `This is a multiline
string in JavaScript.
It also supports expressions.`;
Swift’s multiline strings also support escape characters and maintain indentation, making it easier to format text blocks in a readable way.
String Interpolation: Cleaner and Safer
String interpolation in Swift is both concise and safe. You can embed variables or expressions directly inside strings using \(expression)
:
let name = "Iran"
let greeting = "Hello, \(name)!" // "Hello, Iran!"
This is similar to template literals in JavaScript:
const name = "Iran";
const greeting = `Hello, ${name}!`; // "Hello, Iran!"
Swift’s strong type system ensures that you cannot interpolate unsupported types without proper conversion, which reduces the risk of runtime errors.
Operators: Arithmetic, Iteration, and Comparison
Arithmetic operators in Swift behave similarly to JavaScript:
let sum = 1 + 2
let concatenated = "Hello, " + "world!"
However, Swift ensures type safety, meaning you can’t accidentally mix types (e.g., 1 + "2"
). In JavaScript, type coercion can lead to surprising results:
1 + "2"; // "12" in JavaScript due to implicit conversion
In Swift, this would throw a compile-time error unless you explicitly cast the types:
let result = String(1) + "2" // "12"
This eliminates bugs caused by implicit type coercion that are common in JavaScript.
Ternary Operator: Pretty much the same
The ternary operator in Swift works exactly as it does in JavaScript. It provides a shorthand for conditional expressions:
let isEven = (number % 2 == 0) ? "Even" : "Odd"
In JavaScript, this would look the same:
const isEven = (number % 2 === 0) ? "Even" : "Odd";
Both languages use the same syntax and behavior for the ternary operator, making it a familiar feature when transitioning between the two.
Logical Operators: Familiar but Strict
Logical operators in Swift are similar to those in JavaScript, using &&
for AND, ||
for OR, and !
for NOT:
let isAdult = age >= 18 && hasID
In JavaScript, it’s the same:
const isAdult = age >= 18 && hasID;
However, Swift does not have truthy or falsy values like JavaScript. In JavaScript, expressions like 0
, ""
, or null
are evaluated as falsy in conditionals, while in Swift, the condition must be a strict Bool
.
Range Operators: Iteration and more
Closed range
In Swift, ranges are a useful feature for iterating over sequences of numbers. These are particularly useful when combined with loops:
for index in 1...5 {
print(index) // 1 2 3 4 5
}
This range behavior is not directly available in JavaScript. You’d typically use a for
loop or array methods like map
or forEach
in JS:
for (let i = 1; i <= 5; i++) {
console.log(i); // 1 2 3 4 5
}
Half-open range
A half-open range in Swift includes the starting value but excludes the ending value. This is especially useful when you want to avoid off-by-one errors:
for index in 1..<5 {
print(index) // 1 2 3 4
}
In JavaScript, you would have to manually adjust the condition to exclude the upper bound:
for (let i = 1; i < 5; i++) {
console.log(i); // 1 2 3 4
}
Slicing through ranges
Swift's ranges also make it easy to slice collections, something that JavaScript handles with array methods like slice
:
let names = ["Anna", "Alex", "Brian", "Jack"]
for name in names[2...] {
print(name) // Brian, Jack
}
This can be achieved in JavaScript using array methods like slice, but it’s less concise:
const names = ["Anna", "Alex", "Brian", "Jack"];
names.slice(2); // ["Brian", "Jack"]
Exploring Swift has highlighted some interesting similarities with JavaScript, especially when it comes to things like immutability, type safety, and how operators work. Even though Swift has its own unique features and some strict rules about types, a lot of the core ideas feel pretty similar.
In my next post, I'll be exploring Swift's collection types like arrays, dictionaries, sets, and enums. Stay tuned!