Generics
Generics let you write code once that works with any type — without giving up type safety. You'll write generic functions and types with <T> , add type constraints , and refine them with where clauses.
Learn Generics in our free Swift course — a beginner-friendly interactive lesson with worked examples, a practice exercise and a quick reference.
Part of the free Swift course at LearnCodingFast — hands-on lessons with examples you run in your browser, plus practice exercises and a quick quiz.
What You'll Learn in This Lesson
- • Write generic functions with a type placeholder <T>
- • Build generic types like Stack<Element>
- • Add type constraints such as <T: Comparable>
- • Refine generics with where clauses
- • See why generics beat Any for type safety
- • Recognize associatedtype in protocols
1️⃣ Generic Functions
Put a placeholder in angle brackets after the function name — <T> — and use T wherever a concrete type would go. The same function then works with arrays of any element type.
A classic generic is a swap. One function handles every type instead of one per type.
2️⃣ Type Constraints
Sometimes you need the placeholder to support an operation. A constraint like <T: Comparable> guarantees T conforms to a protocol, unlocking its operators and methods.
3️⃣ Generic Types
Types can be generic too. A Stack<Element> stores any kind of value, and you choose the element type when you create one.
Your turn. Fill in the blanks to make a function generic and to add a constraint.
Pro Tips
- 💡 Name placeholders meaningfully. Element , Key , Value beat a bare T in types.
- 💡 Constrain only as much as needed. Add : Comparable when you actually compare.
- 💡 Prefer generics over Any to keep compile-time safety.
- 💡 Use where for constraints on associated/element types.
Common Errors (and the fix)
- "Binary operator '>' cannot be applied to two 'T' operands" — add a constraint: <T: Comparable> .
- "Cannot convert value of type 'Int' to expected argument type 'String'" — using the same T forces both arguments to match.
- "Reference to generic type 'Stack' requires arguments" — specify the element type, e.g. Stack<Int>() (or let it be inferred).
- Using Any then needing a cast — switch to a generic to keep the real type.
📋 Quick Reference
Task
Code
Note
Generic func
func f<T>(_ x: T)
placeholder T
Generic type
struct Box<T> { … }
any element
Constraint
<T: Comparable>
must conform
where clause
where Element == Int
extra rule
Use it
Stack<String>()
fill the type
Frequently Asked Questions
Mini-Challenge: Generic Pair
No blanks this time — just a brief and an outline. Build it, run it, and check your output against the example in the comments.
🎉 Lesson Complete!
- ✅ Generics write code once that works with any type
- ✅ <T> is a type placeholder filled at the call site
- ✅ Types can be generic too: Stack<Element>
- ✅ Constraints like <T: Comparable> unlock protocol operations
- ✅ where clauses add finer requirements
- ✅ Next lesson: Protocol-Oriented Programming
Practice quiz
What problem do generics solve?
- Slow runtime
- Memory leaks
- Writing flexible, reusable code that works with any type
- Optional unwrapping
Answer: Writing flexible, reusable code that works with any type. Generics let you write code once that works with many types, avoiding duplication.
What does <T> mean in a generic function?
- A type placeholder filled in when the function is called
- A fixed type named T
- A tuple
- A constant
Answer: A type placeholder filled in when the function is called. T is a type parameter — a placeholder the caller's type fills in.
Is Array a generic type?
- No
- Only Int arrays are
- Only in extensions
- Yes — Array<Element> is generic over its element type
Answer: Yes — Array<Element> is generic over its element type. Array<Element> and Dictionary<Key, Value> are generic standard-library types.
What is a type constraint?
- A way to forbid generics
- A requirement that a type parameter conform to a protocol or class
- A runtime check
- An optional
Answer: A requirement that a type parameter conform to a protocol or class. A constraint like <T: Equatable> requires the type parameter to conform to a protocol.
How do you require T to be comparable with < ?
- <T: Comparable>
- <T>
- <T == Comparable>
- <T?>
Answer: <T: Comparable>. <T: Comparable> constrains T to types that conform to Comparable.
What does a 'where' clause do?
- Declares a variable
- Loops over a collection
- Adds extra requirements on type parameters
- Imports a module
Answer: Adds extra requirements on type parameters. A where clause adds additional constraints, e.g. where T.Element == Int.
Can structs and classes be generic?
- No, only functions
- Yes — you can write generic types like struct Stack<Element>
- Only classes
- Only enums
Answer: Yes — you can write generic types like struct Stack<Element>. Types can be generic too: struct Stack<Element> works with any element type.
Why prefer a generic function over one using Any?
- It's shorter
- Any is faster
- There's no difference
- Generics keep full type information and type safety
Answer: Generics keep full type information and type safety. Generics preserve the concrete type at compile time, so you keep type safety and avoid casts.
In func swapValues<T>(_ a: inout T, _ b: inout T), why must both be T?
- For speed
- So the two values are guaranteed to be the same type
- To allow nil
- It's optional
Answer: So the two values are guaranteed to be the same type. Using the same placeholder T for both ensures the arguments share one type.
What is associatedtype used for?
- Generic functions
- Type casting
- A placeholder type inside a protocol
- Error handling
Answer: A placeholder type inside a protocol. associatedtype declares a placeholder type that a conforming type specifies — generics for protocols.
Continue this course
- Previous: Extensions
- Next: Protocol-Oriented Programming