📖 Scenario: Imagine you are building a simple app that manages different types of shapes. Each shape can calculate its area, but they have different types. You want to store them together and work with them uniformly.
🎯 Goal: You will create a protocol for shapes, implement two different shapes, then use type erasure to store them in a single array and calculate their total area.
📋 What You'll Learn
Create a protocol called Shape with a method area() returning Double
Create two structs Circle and Rectangle conforming to Shape
Create a type-erased wrapper called AnyShape to hold any Shape
Store multiple AnyShape instances in an array and calculate the total area
💡 Why This Matters
🌍 Real World
Type erasure helps when you want to work with different types that share behavior but cannot be stored together directly, such as UI components or data models.
💼 Career
Understanding type erasure is important for Swift developers to write flexible and reusable code, especially when working with protocols and generics.
Progress0 / 4 steps
1
Create the Shape protocol and two shape structs
Create a protocol called Shape with a method area() that returns a Double. Then create two structs: Circle with a radius property, and Rectangle with width and height properties. Both structs must conform to Shape and implement the area() method.
Swift
Hint
Protocols define what methods a type must have. Structs can conform to protocols by implementing those methods.
2
Create the AnyShape type-erased wrapper
Create a struct called AnyShape that conforms to Shape. It should have a private property holding a closure for the area() method. Add an initializer that accepts any Shape and stores its area() method in the closure.
Swift
Hint
Type erasure uses a wrapper that hides the specific type but keeps the behavior by storing closures.
3
Create an array of AnyShape and calculate total area
Create an array called shapes of type [AnyShape]. Add a Circle with radius 3 and a Rectangle with width 4 and height 5, wrapped as AnyShape. Then create a variable totalArea and use a for loop with variables shape to sum all areas from shapes.
Swift
Hint
Wrap each shape in AnyShape to store them together. Use a loop to add their areas.
4
Print the total area
Write a print statement to display the text Total area: followed by the value of totalArea.
Swift
Hint
Use string interpolation with print("Total area: \(totalArea)") to show the result.
Practice
(1/5)
1. What is the main purpose of type erasure in Swift?
easy
A. To convert classes into structs automatically
B. To create new types from existing ones
C. To improve runtime performance by avoiding protocols
D. To hide specific types behind a common interface
Solution
Step 1: Understand type erasure concept
Type erasure is used to hide the concrete underlying type and expose a common interface.
Step 2: Identify the main purpose
This allows different types to be used uniformly without exposing their specific details.
Final Answer:
To hide specific types behind a common interface -> Option D
Quick Check:
Type erasure = hiding types behind interface [OK]
Hint: Type erasure hides types to unify usage [OK]
Common Mistakes:
Confusing type erasure with type conversion
Thinking it improves performance directly
Assuming it creates new types
2. Which of the following is the correct syntax to create a type-erased wrapper for a protocol MyProtocol?
easy
A. struct AnyMyProtocol: MyProtocol { private let _base: any MyProtocol }
B. struct AnyMyProtocol<T>: MyProtocol { private let _base: T }
C. struct AnyMyProtocol: MyProtocol { private let _base: MyProtocol }
D. struct AnyMyProtocol: MyProtocol { private let _base: some MyProtocol }
Solution
Step 1: Recall type erasure syntax
Type erasure uses a struct that conforms to the protocol and stores an instance of any Protocol to hide the concrete type.
Step 2: Identify correct syntax
struct AnyMyProtocol: MyProtocol { private let _base: any MyProtocol } uses any MyProtocol which is the correct way to store an existential type in Swift 5.7+.
Final Answer:
struct AnyMyProtocol: MyProtocol { private let _base: any MyProtocol } -> Option A
Quick Check:
Use any Protocol for type erasure storage [OK]
Hint: Use 'any Protocol' to store erased type [OK]
B. Cannot assign generic method to closure with Any parameter
C. Cannot use associatedtype in protocol
D. Function printItem has wrong return type
Solution
Step 1: Analyze closure assignment
The closure _print expects (Any) -> Void but printer.printItem expects (P.Item) -> Void, which is a mismatch.
Step 2: Understand type erasure limitation
Associated types prevent direct assignment because the types differ; you cannot assign a generic method to a closure with Any parameter.
Final Answer:
Cannot assign generic method to closure with Any parameter -> Option B
Quick Check:
Generic method ≠ closure with Any parameter [OK]
Hint: Generic methods can't be assigned to Any closures directly [OK]
Common Mistakes:
Thinking protocol conformance is missing
Confusing associatedtype usage
Assuming return type mismatch
5. You want to create a type-erased wrapper for a protocol DataSource with an associated type Item and a method func fetch() -> [Item]. Which approach correctly applies type erasure to allow storing different DataSource implementations in a single array?
hard
A. Create a struct AnyDataSource with a private closure _fetch: () -> [Any] and cast results inside
B. Use a generic struct AnyDataSource<T> storing DataSource directly
C. Create a struct AnyDataSource with a private closure _fetch: () -> [Item] and use type erasure with a generic initializer
D. Use protocol inheritance to remove associated type
Solution
Step 1: Understand associated type challenge
Protocols with associated types cannot be used directly in collections because the type varies.
Step 2: Apply type erasure pattern
Create a struct with a private closure returning [Item], and initialize it generically to wrap any DataSource, hiding the concrete type.
Step 3: Evaluate options
Create a struct AnyDataSource with a private closure _fetch: () -> [Item] and use type erasure with a generic initializer correctly uses a generic initializer and closure with [Item], preserving type safety and enabling storage in arrays.
Final Answer:
Create a struct AnyDataSource with a private closure _fetch: () -> [Item] and use type erasure with a generic initializer -> Option C
Quick Check:
Type erasure with generic init and closure = Create a struct AnyDataSource with a private closure _fetch: () -> [Item] and use type erasure with a generic initializer [OK]
Hint: Use generic init and closure returning [Item] for erasure [OK]
Common Mistakes:
Casting to [Any] loses type safety
Using generic struct prevents uniform storage
Trying to remove associated type via inheritance
Recommended
Ready to prove it?
Pass the test and this pattern moves unknownstrongwhile earning +1 Grip toward your certificate.