
Learning Swift from a C# Perspective
Mutability of Collections #
1. Core Concepts #
- Concept Explanation: In Swift, the mutability of collections (Arrays, Sets, Dictionaries) depends entirely on whether they are declared as a variable (
var) or a constant (let). This is independent of the collection’s type definition but determined by the declaration method. - Key Syntax:
var(Mutable),let(Immutable) - Official Tip:
Creating immutable collections is a good practice. It not only makes the program logic clearer but also allows the Swift compiler to optimize performance for immutable collections.
2. Example Analysis #
Source Code:
// If declared as var, the collection can be modified after creation (add, remove, change items)
var mutableArray = [1, 2, 3]
mutableArray.append(4)
// If declared as let, the collection's size and content cannot be changed
let immutableArray = [1, 2, 3]
// immutableArray.append(4) // This line will report an errorLogic Explanation: This code demonstrates that var grants the ability to modify the collection’s content, while let completely locks down the content and length.
3. C# Developer Perspective #
Concept Mapping: The C# readonly keyword is fundamentally different from Swift’s let behavior.
C# Comparison:
// C#
public class CollectionExample {
// Even if readonly, the content of the List can still be modified
public readonly List<int> numbers = new List<int> { 1, 2, 3 };
public void Modify() {
numbers.Add(4); // In C#, this is legal! readonly only protects the reference from being reassigned
}
}Key Differences Analysis:
- Syntax: Swift’s
letdeclaration for collections represents true “Deep Immutability”. - Behavior: This is because Swift collection types are Structs (Value Types), whereas C# collections are Classes (Reference Types). In Swift, assigning an Array to
letmeans this Value Type instance cannot be altered at all; in C#, areadonly Listonly means you cannot point the variable to another List object, but the internal data of the original List can be modified. To achieve the effect of Swift’sletin C#, you typically needImmutableList<T>orReadOnlyCollection<T>.
Arrays #
1. Core Concepts #
- Concept Explanation: An Array is an ordered list that allows storing duplicate values. Swift’s Array is a generic collection.
- Key Syntax:
[Element],Array<Element>,append,+=, Subscript syntax[] - Official Tip:
Swift’s Array type is bridged to Foundation’s NSArray class.
2. Example Analysis #
Source Code:
// Shorthand syntax and initialization
var shoppingList: [String] = ["Eggs", "Milk"]
// Use append to add
shoppingList.append("Flour")
// Use += to concatenate arrays
shoppingList += ["Baking Powder", "Chocolate Spread", "Cheese", "Butter"]
// Use Range Subscript to modify values within a range
shoppingList[4...6] = ["Bananas", "Apples"]
// Replace the three elements from index 4 to 6 with two new elementsLogic Explanation:
- Swift prefers the
[Type]shorthand syntax. - The
+=operator can be used to concatenate arrays, which is very intuitive. - The most powerful feature is
Range Subscript, which allows directly replacing a range within an array, and the new content length does not have to match the original range length (as seen in the example where 3 elements are replaced by 2).
3. C# Developer Perspective #
Concept Mapping: Swift’s Array corresponds to C#’s List<T>, not C#’s primitive array T[].
C# Comparison:
// C#
var shoppingList = new List<string> { "Eggs", "Milk" };
shoppingList.Add("Flour");
shoppingList.AddRange(new [] { "Baking Powder", "Chocolate Spread" });
// C# List does not have native Range Assignment syntax; typically requires RemoveRange + InsertRange
shoppingList.RemoveRange(4, 3);
shoppingList.InsertRange(4, new [] { "Bananas", "Apples" });Key Differences Analysis:
- Syntax: Swift’s
+=for array concatenation is cleaner than C#’sAddRange. Swift’s Range Subscript ([4...6] = ...) is a feature C# developers will envy. - Behavior: This is the biggest pitfall. Swift Arrays are Value Types; C#’s
List<T>are Reference Types.- In Swift:
var a = [1]; var b = a; b.append(2);->aremains[1], onlybchanges (Copy-on-Write mechanism). - In C#:
var a = new List<int>{1}; var b = a; b.Add(2);->aalso becomes[1, 2]because they point to the same object.
- In Swift:
Sets #
1. Core Concepts #
- Concept Explanation: A Set is an unordered collection of unique elements. Types stored in a Set must conform to the
Hashableprotocol to verify uniqueness via hash values. - Key Syntax:
Set<Element>,insert,intersection,union,symmetricDifference
2. Example Analysis #
Source Code:
var favoriteGenres: Set<String> = ["Rock", "Classical", "Hip hop"]
// Set operations
let oddDigits: Set<Int> = [1, 3, 5, 7, 9]
let evenDigits: Set<Int> = [0, 2, 4, 6, 8]
// Intersection
oddDigits.intersection(evenDigits).sorted() // []
// Union
oddDigits.union(evenDigits).sorted() // [0, 1, ..., 9]Logic Explanation: Swift provides set operations (intersection, union, difference) directly as core methods of Set, with syntax very close to mathematical definitions.
3. C# Developer Perspective #
Concept Mapping: Corresponds to C#’s HashSet<T>.
C# Comparison:
// C#
var favoriteGenres = new HashSet<string> { "Rock", "Classical", "Hip hop" };
var oddDigits = new HashSet<int> { 1, 3, 5, 7, 9 };
var evenDigits = new HashSet<int> { 0, 2, 4, 6, 8 };
// C#'s HashSet modifies itself directly (UnionWith, IntersectWith)
// To generate a new set, use LINQ or a copy constructor
var union = new HashSet<int>(oddDigits);
union.UnionWith(evenDigits);Key Differences Analysis:
- Syntax: Swift’s
Sethas no shorthand initialization syntax (like[Type]for Array). You must writeSet<Type>, though you can use Array Literals[]for assignment. - Behavior: Swift’s set operation methods (like
union) usually return a new Set (Functional style), whereas C#’sHashSetmethods (likeUnionWith) are usuallyvoidand modify the current instance (Imperative style). To modify the set itself in Swift, use methods prefixed withform, such asformUnion.
Dictionaries #
1. Core Concepts #
- Concept Explanation: An unordered collection storing Key-Value pairs. Keys must be
Hashable. - Key Syntax:
[Key: Value],updateValue,removeValue, Subscript key access - Official Tip:
Accessing a dictionary using Subscript syntax returns an Optional value because the Key might not exist.
2. Example Analysis #
Source Code:
var airports: [String: String] = ["YYZ": "Toronto Pearson", "DUB": "Dublin"]
// Add or modify
airports["LHR"] = "London"
// Use updateValue to get the old value
if let oldValue = airports.updateValue("Dublin Airport", forKey: "DUB") {
print("Old value was \(oldValue)")
}
// Access value (returns Optional)
if let airportName = airports["DUB"] {
print("Airport is \(airportName)")
} else {
print("Not found")
}
// Remove
airports["APL"] = nil // Setting to nil removes itLogic Explanation:
[Key: Value]is standard shorthand.updateValueis useful; it returns “the value before the update,” suitable for logging or logic checks.- Setting a Key’s value to
nilis equivalent to deleting that Key from the dictionary.
3. C# Developer Perspective #
Concept Mapping: Corresponds to C#’s Dictionary<TKey, TValue>.
C# Comparison:
// C#
var airports = new Dictionary<string, string> {
{ "YYZ", "Toronto Pearson" },
{ "DUB", "Dublin" }
};
// Access value - C# indexer throws an Exception if Key does not exist
// string name = airports["INVALID"]; // Throws KeyNotFoundException
// Safe access method
if (airports.TryGetValue("DUB", out string airportName)) {
Console.WriteLine($"Airport is {airportName}");
}
// Remove
airports.Remove("APL"); // Cannot assign null to removeKey Differences Analysis:
- Syntax:
- Swift’s index access
dict[key]always returns Optional, forcing developers to handle cases where the Key doesn’t exist (safer). - C#’s index access
dict[key]assumes the Key exists, otherwise it throws an exception. C# developers must get used toTryGetValueor Swift’s Optional Binding (if let).
- Swift’s index access
- Behavior:
- In Swift,
dict["key"] = nilis a delete operation. - In C#, if the Value Type is a Reference Type,
dict["key"] = nulljust sets that Value to null; the Key remains in the dictionary. This is a very confusing point. - Iteration: Swift iteration yields a Tuple
(key, value), which is easy to destructure; C# yieldsKeyValuePair<TKey, TValue>objects, requiring.Keyand.Valueaccess.
- In Swift,
// Swift Iteration
for (code, name) in airports {
print("\(code): \(name)")
}// C# Iteration
foreach (var kvp in airports) {
Console.WriteLine($"{kvp.Key}: {kvp.Value}");
}