Final Project: Build a Tiny Event Emitter with Coroutines
Combine coroutines, metatables, and varargs into a small pub/sub event emitter, a pattern used constantly in game engines and GUI frameworks.
Requirements
- Build an
EventEmitter"class" (metatable-based, like earlier OOP lessons) withon(event, handler),off(event, handler), andemit(event, ...)methods.emitshould forward any extra arguments straight to every registered handler using varargs. - Support multiple handlers per event name, stored in a table keyed by event name, each holding a list of handler functions.
- Wrap each handler call in
pcallinsideemit, so one broken handler doesn't stop the rest of that event's handlers from running, log a warning for the failing one instead. - Add an
onceAsync(event)method that returns a coroutine-based helper: calling it pauses (viacoroutine.yield) until the named event next fires, then resumes with that event's arguments, essentially turning a callback-style event into something you can "await" step by step. - Use a weak table (
__mode = "k") to track any per-listener metadata you add (e.g. a registration timestamp) so that metadata doesn't keep a removed handler function alive forever.
Stretch goals
- Add wildcard subscriptions (
emitter:on("*", handler)fires on every event). - Add a
once(event, handler)convenience method that automatically callsoffafter the handler's first invocation. - Benchmark emitting 10,000 events with
os.clock()before and after switching a hot path frompairstoipairswhere applicable, and note the difference.
Submit a link to your finished script (a repo or gist) below, an instructor will review it before you can mark this lesson complete.