Activity 1
Create a generic helper
Write a function that returns the last element of any array as an optional. Test it with strings and integers.
Hint: The return type should use the same generic element type as the input array.
Swift Fundamentals
Write reusable, type-safe functions and types with generic parameters, constraints, and associated types.
Before you begin
Learning stage
Generics let one implementation work with different concrete types without giving up compile-time safety. A generic parameter such as T is a placeholder that becomes a real type when the function or type is used. Swift can usually infer that type from the arguments.
Constraints describe what a generic value must be able to do. For example, T: Equatable allows an implementation to compare two T values. Use generics when behavior is genuinely independent of the concrete type; use a concrete type when the domain requires one specific representation.
Learning stage
The function accepts any Equatable element while preserving the array's concrete element type.
func firstIndex<T: Equatable>(of target: T, in values: [T]) -> Int? {
for (index, value) in values.enumerated() {
if value == target { return index }
}
return nil
}
print(firstIndex(of: "Swift", in: ["iOS", "Swift", "Xcode"]) ?? -1)
print(firstIndex(of: 30, in: [10, 20, 30]) ?? -1)Learning stage
These concepts appear throughout production iOS code. Focus on the requirement each technique communicates.
Learning stage
Notice these mistakes early so the compiler and type system can help instead of becoming obstacles.
Learning stage
Work through these activities in a small Xcode project. No embedded playground is required on this site.
Activity 1
Write a function that returns the last element of any array as an optional. Test it with strings and integers.
Hint: The return type should use the same generic element type as the input array.
Activity 2
Create a Box<Value> type and an isSame(as:) method available when Value conforms to Equatable.
Hint: Use a constrained extension.
Learning stage
Answer each question before revealing the explanation.
QUESTION 1
They preserve compile-time type information
A generic API remains reusable while the compiler knows the concrete type at each use.
QUESTION 2
Because its implementation needs to compare T values with == or !=.
Constraints grant the generic implementation access to specific capabilities.
Learning stage
Explain the idea in terms of its purpose, behavior, and tradeoffs rather than reciting syntax.
Short answer: Choose generics when one implementation should preserve the caller's concrete type and use capabilities expressed through constraints.
Generics provide compile-time specialization and keep relationships between input and output types. A protocol existential is useful when heterogeneous values need one runtime interface. Any removes useful information and should not be a default escape hatch.
Possible follow-ups
Learning stage
Generics express reusable algorithms and containers without erasing type information. Add only the constraints the implementation needs and keep concrete APIs concrete when the domain calls for them.