Structural Typing vs Nominal Typing
Structural vs nominal typing compared — shape checking vs declared names, with Java, Go, and TypeScript examples and tradeoffs.
Expected Interview Answer
Structural typing determines type compatibility by comparing the actual shape of a type — its methods and properties — while nominal typing determines compatibility strictly by declared name and explicit inheritance or interface implementation, regardless of shape.
Under nominal typing, used by Java, C#, and C++, a class is only considered a subtype of an interface if it explicitly declares implements or extends that interface, even if it happens to have every required method with matching signatures. Under structural typing, used by TypeScript, Go interfaces, and Python’s typing.Protocol, a type automatically satisfies an interface simply by having the matching members, with no explicit declaration required — this is essentially duck typing enforced at compile time rather than left to fail at runtime. Structural typing gives more flexibility for retrofitting unrelated types into an interface after the fact, since you never need to modify the original type’s declaration, while nominal typing gives stronger intent-revealing guarantees and prevents accidental compatibility between types that merely share a shape by coincidence. Many languages blend both: Java is nominal for interfaces but structurally checks generic bounds in some contexts, and Go is fully structural for interfaces while still nominal for named struct types.
- Structural typing enables retrofitting unrelated types without modifying their declarations
- Nominal typing prevents accidental compatibility from coincidental shape matches
- Structural typing supports duck-typing style flexibility checked at compile time
- Nominal typing communicates intent explicitly through declared implements/extends
AI Mentor Explanation
Nominal typing is like a selector who only considers a player 'a certified all-rounder' if they hold an official all-rounder certificate on file, even if a specialist batsman quietly has excellent bowling skills too. Structural typing is like a selector who instead just watches a trial match and declares anyone who can both bat and bowl well an all-rounder on the spot, certificate or not. The nominal selector demands the explicit paperwork; the structural selector only cares whether the actual skills are present. That is the essential difference between checking a declared name versus checking the actual shape of ability.
Step-by-Step Explanation
Step 1
Nominal check: look at the declaration
The language checks whether the type explicitly declares implements/extends the target type or interface.
Step 2
Structural check: look at the shape
The language instead inspects whether the type actually has the required methods/properties with matching signatures.
Step 3
Nominal rejects shape-only matches
Even an identical-shaped type is incompatible under nominal typing without the explicit declaration.
Step 4
Structural accepts unrelated shape matches
Any type with the right shape satisfies a structural interface automatically, even if authored independently.
What Interviewer Expects
- Correct definition contrasting declared-name checking vs shape checking
- Concrete language examples on each side (Java/C# nominal, TypeScript/Go structural)
- Awareness of the tradeoffs: intent-revealing safety vs retrofit flexibility
- Recognition that some languages mix both approaches
Common Mistakes
- Confusing structural typing with dynamic/duck typing at runtime (structural typing is checked statically at compile time in TS/Go)
- Assuming all statically typed languages are nominal
- Not knowing Go interfaces are structurally satisfied with no implements keyword
- Overstating that structural typing has no safety — it still enforces exact shape matching
Best Answer (HR Friendly)
“Nominal typing checks whether a type explicitly declares that it implements a particular interface or extends a class — the name and declaration matter, not just the shape. Structural typing instead checks whether a type actually has the right methods and properties, and if it does, it’s automatically considered compatible, no explicit declaration needed. Java and C# are nominal, while TypeScript and Go use structural typing, and each approach trades off some safety for flexibility differently.”
Code Example
interface Flyable {
void fly();
}
class Bird implements Flyable { // explicit declaration required
public void fly() { System.out.println("Bird flies"); }
}
class Drone {
// Same method shape as Flyable, but no "implements Flyable"
public void fly() { System.out.println("Drone flies"); }
}
// Compile error: Drone is NOT a Flyable under nominal typing,
// even though it has a matching fly() method.
// Flyable f = new Drone();
Flyable f = new Bird(); // OK: explicit declaration satisfies nominal typingFollow-up Questions
- Why does Go use structural typing for interfaces but nominal typing for struct identity?
- How does TypeScript's structural typing differ from JavaScript's runtime duck typing?
- What safety risk does structural typing introduce that nominal typing avoids?
- Can you make a nominally typed language behave more structurally (e.g. via generics or reflection)?
MCQ Practice
1. Nominal typing determines compatibility based on?
Nominal typing requires an explicit implements/extends declaration, regardless of matching shape.
2. Which of these languages uses structural typing for interfaces?
Go interfaces are satisfied automatically by any type with matching methods, with no explicit implements keyword.
3. A key benefit of structural typing is?
Structural typing lets an already-existing type satisfy an interface simply by shape, without editing its declaration.
Flash Cards
Nominal typing in one line? — Type compatibility determined by explicit declared name (implements/extends).
Structural typing in one line? — Type compatibility determined by matching shape (methods/properties), no explicit declaration needed.
Example nominal languages? — Java, C#, C++.
Example structural languages? — TypeScript, Go (interfaces), Python (typing.Protocol).