Although event-driven programming is a paradigm that is extremely common for asynchronous systems, it doesn't mean that every event-driven application must be asynchronous. It also doesn't mean that event-driven programming is suited only for concurrent and asynchronous applications. Actually, the event-driven approach is extremely useful, even for decoupling problems that are strictly synchronous and definitely not concurrent.
Consider, for instance, database triggers that are available in almost every relational database system. A database trigger is a stored procedure that is executed in response to a certain event that happens in the database. This is a common building block of database systems that, among others, allows the database to maintain data consistency in scenarios that cannot be easily modeled with the mechanism of database constraints. For instance, the PostgreSQL database distinguishes three types of row-level events that can occur in either a table or a view:
- INSERT
- UPDATE
- DELETE
In the case of table rows, triggers can be defined to be executed either BEFORE or AFTER a specific event. So, from the perspective of event-procedure coupling, we can treat each AFTER/BEFORE alternative as a separate event. To better understand this, let's consider the following example of database triggers in PostgreSQL:
CREATE TRIGGER before_user_update BEFORE UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE check_user();
CREATE TRIGGER after_user_update AFTER UPDATE ON users FOR EACH ROW EXECUTE PROCEDURE log_user_update();
In the preceding example, we have two triggers that are executed when a row in the users table is updated. The first one is executed before a real update occurs and the second one is executed after the update is done. This means that both events are casually dependent and cannot be handled concurrently. On the other hand, similar sets of events occurring on different rows from different sessions can still be concurrent. Whether triggers coming from different sessions are independent and whether they can be processed asynchronously depends on multiple factors (transaction or not, isolation level, and many more), and is really up to the database system. But it doesn't mean that the system as a whole cannot be modeled as if the events were truly independent.
In the next section, we'll take a look at event-driven programming in GUIs.