Interface-Driven Design: A Walkthrough of Epic's Community Tutorial
The main lesson taught you interface syntax; this piece answers the harder question: when should you extract an interface? We walk through the design thinking of Epic's community tutorial "Implementing an Interface in Verse Code", line it up against the three values the official docs highlight, and finish with the engine interfaces you use every day without ever noticing.
1. What the Tutorial Is Doing: One Contract, Many Ways to Deliver
Epic's community tutorial boils down to three steps: define the contract → implement individually → hold uniformly. First use interface (i.e. a Blueprint Interface, BPI) to write down "what every signer must be able to do"; then let several mutually unrelated Blueprints each fulfill the contract with <override>; finally the calling side holds them all through one reference of the interface type, never asking who is behind it. Here is that skeleton rebuilt with a "damageable" example:
using { /UnrealEngine.com/Temporary/Diagnostics }
# Step 1: the contract - every damageable thing must be able to take a hit
damageable := interface:
TakeHit(Amount:int):void
# Step 2: each delivers - the training dummy and the barrel share no ancestry
training_dummy := class(damageable):
TakeHit<override>(Amount:int):void =
Print("Training dummy calmly soaks up {Amount} damage")
exploding_barrel := class(damageable):
TakeHit<override>(Amount:int):void =
Print("Barrel takes the hit and explodes!")
# Step 3: hold them uniformly - the caller sees the contract, not the concrete type
HitAll(Targets:[]damageable, Amount:int):void =
for (T : Targets):
T.TakeHit(Amount)
Reading the code: three blocks, three steps: first build the interface damageable (the contract: can TakeHit); then two Blueprints with zero shared ancestry, training_dummy and exploding_barrel, each signing the deal and implementing TakeHit with <override> as its own reaction (one calmly soaks it up, the other blows sky-high on the spot); finally HitAll receives a []damageable array and calls TakeHit on each with a ForEach — it only honors the "you can take a hit" contract and never asks who you specifically are.
Note HitAll's parameter type: []damageable — the type of every array slot is the interface. Training dummies, barrels, and whatever comes later — targets, scarecrows, mirror clones… as long as they sign this contract, they get into that array and get handled by that function. Add a new damageable and HitAll doesn't change by a single character — that is the core payoff of interface-driven design: cleanly separating "the part that changes" (each Blueprint's own implementation) from "the part that doesn't" (the calling logic).
2. The Official Docs' Highlights: Three Values of Interfaces
The official "Interface in Verse" documentation credits interfaces with three values, each worth translating into plain speech:
▢ Safety. An interface shows only the contract, never the inner workings: whoever holds a damageable reference can call the TakeHit the contract promised and nothing else — the barrel's internal fuse state stays out of reach. The smaller the exposed surface, the fewer ways anyone can misuse it.
▢ Multiple inheritance. A Verse class gets only one parent class yet can implement any number of interfaces at once: class(base, iface1, iface2) — that Implemented Interfaces list in a Blueprint's Class Settings where you can tick a whole column. A boss can be both damageable and pickup (drops itself on death? why not), two capabilities composed onto one Blueprint without interfering — a freedom plain parent-class inheritance can't offer.
▢ Reusability. Every piece of logic written against the interface (HitAll, loot settlement, UI lists…) automatically applies to every Blueprint that signs the contract, now and in the future. Write once, feast forever.
3. When to Extract an Interface: A Checklist
More interfaces are not better — extracting an interface for something with only one implementation is like wearing a raincoat in the shower. Check this list before you reach for one:
- Two or more unrelated classes need the same capability (coins and potions can both be picked up) → extract an interface.
- The side using it only cares "can it do this", not "who is it" (the settlement function only needs the other side to TakeHit) → write the interface as the type of parameters and array slots.
- You want to add a capability to an existing inheritance line without touching its parent class → an interface can be layered on top:
class(base, iface). - Counter-example: there is only one implementation and you can't imagine a second → don't extract; write it in the class and refactor when the second implementation shows up.
- Counter-example: the Blueprints implementing it need shared fields, or one shared default behavior → an interface can't provide those (no fields, no node graphs allowed); that calls for an
<abstract>class.
One sentence to sum up: express shared behavior with an interface, shared data and implementation with a parent class. The two can fight side by side — the parent class handles ancestry, the interfaces (BPIs) handle skills.
4. Interfaces You Use Every Day: A Tour of the Official API
Interface-driven design is no tutorial toy; Epic's own API is written this way. Open the Verse API Reference and familiar faces appear: fort_character — character capabilities (health, teleport, movement) are defined as an interface, so "characters" of every form can be driven uniformly; listenable(payload) — InteractedWithEvent.Subscribe(...) (binding a device event to your own handler; this is Blueprint's Event Dispatcher / Bind Event, covered in depth in Lesson 25) rests on exactly this parameterized "listenable" contract; enableable — the Enable / Disable on scores of devices comes from one shared "can be toggled" contract, which is why you can switch a batch of different device types on and off with a single piece of code.
Next time you call an API, spare a glance for the parameter types: when a parameter's type is an interface, Epic is really telling you "this slot honors the contract, not the person" — a Blueprint of your own, once it signs that contract, slides right in. Read at that level, and the way you read API docs upgrades from "looking up functions" to "reading the design".
Which of these can an interface do that an <abstract> class cannot?
Sources & Further Reading
Compiled from Epic's community tutorial and official documentation:
▸ Community tutorial: Implementing an Interface in Verse Code ↗