
Learning Swift from a C# Perspective
Subscript Syntax #
1. Core Concepts #
- Concept Explanation:
Swift Subscripts allow you to quickly access member elements within a Class, Structure, or Enumeration using brackets
[]. This is the mechanism behind accessing an Array viasomeArray[index]or a Dictionary viasomeDictionary[key]. You do not need to explicitly define methods likegetX/setX; instead, a subscript unifies the description of access behavior. - Key Syntax:
subscript,get,set,newValue
2. Example Analysis #
Documentation Source Code:
struct TimesTable {
let multiplier: Int
subscript(index: Int) -> Int {
return multiplier * index
}
}
let threeTimesTable = TimesTable(multiplier: 3)
print("six times three is \(threeTimesTable[6])")
// Prints "six times three is 18".Logic Explanation:
This code defines a structure named TimesTable to calculate a multiplication table.
- The
subscriptkeyword is used to define subscript behavior. - The
getkeyword is omitted here, indicating this is a Read-Only subscript. - When we call
threeTimesTable[6], Swift executes the logic inside thesubscriptblock and returns the result of3 * 6.
Note A multiplication table is based on fixed mathematical rules, so setting
threeTimesTable[someIndex]to a new value does not make sense. Therefore, theTimesTablesubscript is defined as read-only.
3. C# Developer’s Perspective #
Concept Mapping:
Swift’s subscript corresponds directly to C# Indexers (this[...]).
C# Comparison Code:
public struct TimesTable
{
private readonly int _multiplier;
public TimesTable(int multiplier)
{
_multiplier = multiplier;
}
// C# Indexer
public int this[int index]
{
get { return _multiplier * index; }
// Read-only, so set is not implemented
}
}
var threeTimesTable = new TimesTable(3);
Console.WriteLine($"six times three is {threeTimesTable[6]}");Key Differences Analysis:
- Syntax:
- Definition: C# uses the
thiskeyword with bracketspublic int this[int index]; Swift uses the specific keywordsubscript, and the syntax resembles a function definition:subscript(index: Int) -> Int. - Parameter Names: C# indexer parameter names are used internally; Swift parameter names are used for internal logic but can also have external Argument Labels (like function parameters), although labels are usually omitted in calls by default.
- Definition: C# uses the
- Behavior:
- The logic for defining
getandsetis very similar. Swift’ssethas a defaultnewValueparameter, which is completely consistent with thevaluekeyword in C#.
- The logic for defining
Subscript Usage and Dictionary #
1. Core Concepts #
- Concept Explanation:
The specific meaning of a subscript depends on the context. Its most common use is as a shortcut for Collections. You can implement subscripts freely based on business logic. Swift’s
Dictionaryuses subscripts to set and retrieve Key-Value pairs. - Key Syntax:
Dictionary,Optional,nil
2. Example Analysis #
Documentation Source Code:
var numberOfLegs = ["spider": 8, "ant": 6, "cat": 4]
numberOfLegs["bird"] = 2Logic Explanation: This code demonstrates subscript usage with a dictionary.
numberOfLegsis a dictionary of type[String: Int].- Through
numberOfLegs["bird"] = 2, we use subscript syntax to add a new key-value pair.
Note The subscript implemented by Swift’s Dictionary type returns an Optional type (e.g.,
Int?). This is because the Key you are querying might not exist in the dictionary. The Swift Dictionary subscript accepts an Optional when setting, allowing you to assignnilto express the semantics of “removing an element.”
3. C# Developer’s Perspective #
Concept Mapping:
This corresponds to the indexer operation of C# Dictionary<TKey, TValue>, but the behavior when handling “Key does not exist” differs significantly.
C# Comparison Code:
var numberOfLegs = new Dictionary<string, int>
{
{ "spider", 8 },
{ "ant", 6 },
{ "cat", 4 }
};
numberOfLegs["bird"] = 2; // Set or add value, syntax is the same
// However, behavior differs when reading:
// int legs = numberOfLegs["dragon"]; // C# throws KeyNotFoundExceptionKey Differences Analysis:
- Behavior (Crucial):
- Swift:
dictionary[key]returns an Optional (e.g.,Int?). If the Key does not exist, it returnsniland does not crash. This forces developers to handle the possibility of the value being empty. - C#:
dictionary[key]throws aKeyNotFoundExceptionimmediately if the Key does not exist during a read operation. C# developers usually need to defend against this usingContainsKeyorTryGetValue.
- Swift:
- Removing Elements: Swift can remove an element via
dict[key] = nil; C# must calldict.Remove(key). Setting a value tonull(if it is a Reference type) does not remove the Key itself.
Subscript Options and Multiple Parameters #
1. Core Concepts #
- Concept Explanation: Subscripts can accept any number of parameters, and parameters can be of any type. This is known as subscript overloading. This is particularly useful when dealing with multi-dimensional data structures (like matrices).
- Key Syntax:
assert,Multiple Parameters - Official Hint:
Subscripts can use Variadic Parameters and default parameter values, but cannot use
in-outparameters.
2. Example Analysis #
Documentation Source Code:
struct Matrix {
let rows: Int, columns: Int
var grid: [Double]
init(rows: Int, columns: Int) {
self.rows = rows
self.columns = columns
grid = Array(repeating: 0.0, count: rows * columns)
}
func indexIsValid(row: Int, column: Int) -> Bool {
return row >= 0 && row < rows && column >= 0 && column < columns
}
subscript(row: Int, column: Int) -> Double {
get {
assert(indexIsValid(row: row, column: column), "Index out of range")
return grid[(row * columns) + column]
}
set {
assert(indexIsValid(row: row, column: column), "Index out of range")
grid[(row * columns) + column] = newValue
}
}
}
var matrix = Matrix(rows: 2, columns: 2)
matrix[0, 1] = 1.5
matrix[1, 0] = 3.2Logic Explanation:
- The
Matrixstructure stores a flattened 2D matrix in a 1D arraygrid. - A subscript accepting two parameters is defined:
subscript(row: Int, column: Int). assertis used in bothgetandsetto ensure the index is not out of bounds.- When used, parameters are separated by commas:
matrix[0, 1].
3. C# Developer’s Perspective #
Concept Mapping: C# Indexers also support multiple parameters, often used for multi-dimensional arrays or matrix-like structures.
C# Comparison Code:
public struct Matrix
{
private readonly int _rows;
private readonly int _columns;
private double[] _grid;
public Matrix(int rows, int columns)
{
_rows = rows;
_columns = columns;
_grid = new double[rows * columns];
}
public double this[int row, int col]
{
get
{
// Simplified boundary check
return _grid[(row * _columns) + col];
}
set
{
_grid[(row * _columns) + col] = value;
}
}
}
var matrix = new Matrix(2, 2);
matrix[0, 1] = 1.5; // C# syntax is exactly the sameKey Differences Analysis:
- Syntax: At the call site, Swift’s
matrix[0, 1]and C#’smatrix[0, 1]are syntactically identical. - Parameter Restrictions: Swift explicitly forbids
in-outparameters in subscripts, which is similar to the restriction in C# where indexers cannot usereforoutparameters.
Type Subscripts #
1. Core Concepts #
- Concept Explanation: The examples above are all “Instance Subscripts,” meaning you must create an object instance to use them. Swift further supports Type Subscripts, which belong to the “type itself” and are called directly on the type name.
- Key Syntax:
static subscript,class subscript(for class inheritance)
2. Example Analysis #
Documentation Source Code:
enum Planet: Int {
case mercury = 1, venus, earth, mars, jupiter, saturn, uranus, neptune
static subscript(n: Int) -> Planet {
return Planet(rawValue: n)!
}
}
let mars = Planet[4]
print(mars)Logic Explanation:
- Inside the
Planetenumeration, a type subscript is defined usingstatic subscript. - When calling, you do not need to instantiate
Planet; you use the type name directly:Planet[4]. - Here, it uses
rawValueto initialize and force unwrap (!) to return the corresponding planet.
3. C# Developer’s Perspective #
Concept Mapping: This is a feature that C# currently does not possess.
Key Differences Analysis:
- Syntax: C# does not support syntax like
static this[...]. You cannot writeClassName[index]in C#. - Alternatives: In C#, to achieve a similar effect, one typically uses Static Methods or static read-only collections.
// C# Alternative Approach public enum Planet { Mercury = 1, Venus, Earth, Mars, ... } public static class PlanetExtensions { public static Planet Get(int n) { return (Planet)n; } } // Call var mars = PlanetExtensions.Get(4); - Behavior: Swift’s Type Subscripts make the syntax more consistent, extending the concept of “access via index” to the type level. This is a feature that C# developers will find relatively novel and convenient when transitioning.