In this session, we're reviewing the observer pattern, which is the standard imperative way to do event handling. The observer pattern is widely used when views need to react to changes in a model. Variants of it are also called publish/subscribe or model/view controller. Here we have a model, which is some stateful object or set of objects. Then we have views that show some aspect of the model. The model typically doesn't know how views are implemented or how many there are. The views can also change dynamically in number. The task then is whenever the model gets updated, all the views have to be notified so that they can update themselves as well. A typical scheme to do this is to declare the model to be a publisher and the views would be subscribers. Subscriber contacts a publisher to say, I want to be notified of any updates, and when there are updates, a publisher will essentially notify all the subscribers of these updates. Here's an implementation of this principle in Scala. We have two traits, subscriber and publisher. Subscriber is the base traits of all views and they offer a handler method that will be called by the publisher whenever there's a state change in the publisher. Then the trade publisher maintains a set of subscribers, here in this private variable. A subscribe method would add a subscriber to the set. An unsubscribe method called from a subscriber would remove the subscriber from the set. Finally, the publish method would go through all subscribers and for each subscriber, call the handler method that this subscriber has defined here, and the publisher passes itself along as the publisher here. That means a subscriber could actually subscribe to several publishers and when handling is called, it would know what publisher pushed the change, performed this parameter here. Once we have that, we can make BankAccount a publisher. That means that one can subscribe to a BankAccount to be notified of any changes in that account. BankAccount now extends publisher. What else do we have to do? Well, essentially, three things. First is any state change in deposit or withdraw has to call the publish method here and here. That way, all subscribers are notified. Second, when a subscriber is notified, they would like to find out what the current balance on the account is now because it typically wasn't them to have done a deposit or withdrawal method, so they don't know. We will add another method, current balance that just returns the current balance without depositing or withdrawing anything. That's all the changes that we needed to do. Let's use this model to define a subscriber. One example of a subscriber, I call here a consolidator. Let's say you have a list of bank accounts and we want to know at each point, the total balance over all these accounts. Whenever one of these bank accounts changes, then the consolidator should be notified about the change and it should recompute the total balance. Consolidator is a subscriber and as part of its initialization, it will subscribe to each of the bank accounts in observed. For each of the bank accounts, it will add itself as a subscriber. Then we have the variable total, which reflects the total balance in all the accounts in observed. That variable is initialized by the call to compute that follows immediately. Here's the definition of compute. It sets total to the sum of the current balances of all accounts in observed sum. Compute is called once when we start the consolidator, but it will also be called each time one of the accounts changes, that's done by calling compute from handler. If one of the accounts changes, it will publish that change by calling handler and that will recompute the total balance. Finally, the total balance method here is simply a public interface to this private variable total. This one little syntax twist here, this equals underscore. What does that mean? Well, if I would leave out equals underscore like this, then what I would get is not an uninitialized variable, but an abstract variable. That's basically a variable that only has a way to get the variable and to store the variable, but it's not backed by a field, the variable would have to be implemented in a subclass. To have a variable where I just say, well, I choose to not initialize the variable here because it will be initialized later, I write equals underscore. That means don't initialize total yet. That concludes our example. Let's review what we have seen. The good thing about the observer pattern is that it manages to decouple views from state. The views are quite different from the state in the model. It allows us to have a varying numbers of use of a given state, and it was actually quite simple to setup. It's fairly easy to turn the thing like a bank account or another stateful object into a publisher. The downsides of this pattern are, first that it forces imperative style since handlers are unit type, so a handler never returns anything. It can't because it's called from the publisher. Everything a handler does, it has to do with the side-effect. There are quite a lot of moving parts that need to be coordinated. In particular, subscribers are fairly complex classes. A third downside is that the observer pattern, as we've seen it here, really works well only in a single threaded model. Once we add concurrent execution, things get a lot more complicated. If I look back at the consolidator could happen in a concurrent execution is that several handlers will be called in parallel at the same time, maybe, and that means the consolidator has to protect itself from these conditions. Of course, that can be done. We can make it a monitor with synchronized and so on. But it's additional steps that we have to do and those steps have additional downsides like they might produce deadlocks or other unwanted effects and concurrency. Observers in a concurrent scenario are harried. The fourth downside might be that views are still tightly bound to one model where the view update happens immediately. These issues are actually quite relevant because the observer pattern is a little niche thing. For instance, if we look at Adobe, which is the producer of Photoshop with which this recording was made and also of PDF, then we learned that 1/3 of the code in the desktop applications is devoted to event handling. So 1/3 of all code of a pretty humungous codebase. Furthermore, one-half of the bugs are found in this code. Not only is it a lot of code, but it's code that tends to be more difficult and more buggy than the rest. Can we do better? The answer is yeah, maybe. In the next sessions, we'll explore a different way, namely functional reactive programming. That can improve on the imperative view of reactive programming that's embodied in the observer pattern.