In this session, we take a first look what happens when we add state to functional programming. Until now, our programs have been side-effect free. Therefore, the concept of time wasn't important. For all programs that terminate, any sequence of actions would have given the same results. This was also reflected in the substitution model of computation. As a reminder, let's look at that substitution model again. Here, programs are evaluated by rewriting. The most important rewrite rule covers function applications. It says that if you have a function definition with parameters x_1 to x_n and body B somewhere and you have a call to that function with actual arguments values v_1 to v_n, then the program would be rewritten so that the call gets replaced by the body of the function where the former parameters x_1 to x_n are replaced by the actual values v_1 to v_n. That's the substitution model. Let's see it in action, in an example. Say you have the following two functions iterate and square: Iterate applies function f n times on an initial value x. So if n equals 0, then that's x, and otherwise it's iterate n minus 1, f, f of x. Then you have the square functions that you will have seen a lot of times already. Now the call iterate(1, square, 3) gets rewritten as follows. We expand the body, that gives you this, we simplify the if and pick the else branch and simplify the argument here. That gives you this. We convert the square(3) call to its body 3 times 3, and then to a value which gives this call here, which expands in turn to another body with an if then else, where now 0 equals 0 evaluates to true, so that root in the end give you nine. In that sequence, we always picked one particular place where we would do the next rewriting step. But in fact, rewriting could have been done elsewhere. In fact, it can be done anywhere in a term, and all rewritings which terminate lead to the same solution. That's an important result of the Lambda calculus, the theory behind functional programming. It's sometimes called the Church-Rosser theorem or the conference theorem, that's another name. To demonstrate that, let's take the expression that we started with here again, and we have here our sequence that we performed, so that would lead us here. But another possibility would be to say, well, let's just keep the if then else as it is and concentrate on this call first. That expression could also have been rewritten to this expression here by going deep inside the else part and rewriting the square here to 3 times 3. The Church-Rosser theorem, or conference theorem, says that what we can do is, we can then find another reduction sequence from both sides to end in the same result, nine. In other words, it doesn't really matter where you reduce first, you'll always get the same result. That, in turn, tells you that time cannot matter. The sequence of operations is immaterial to the final result that you get. On the other hand, of course, time is around us in the real world. One normally describes the world as a set of objects, some of which have state that changes over the course of time. We say an object has a state if its behavior is influenced by its history. For instance, a bank account has a state because the answer to the question, ''Can I withdraw 100 Swiss francs?'' might vary over the course of the lifetime of the account. Initially, it might be false because I have no money in, then I might do a deposit then it will be true, and if I withdraw and the account is overdrawn, then the answer might become false again. So the answer to that question depends on the previous history of operations on that account. That was a very abstract notion what it means to have a state, namely to be influenced by one's history. But in practice, and if we disregard input output, then every form of mutable state comes down to be constructed from variables. A variable definition in Scala is written like a value definition, but with the keyword var instead of val. Here you have a variable, here you have another one. Just like a value definition, a variable definition associates a value with a name. If it would be just that, then the variable definitions would behave like two vals. But in the case of variable definitions, this association can be changed later through an assignment. Assignments look like in Java with a single equal sign. You could write letter x equals hi, and then after that statement is executed, the variable x would have the value hi and no longer abc. Or you could write count equals count plus one and then after that statement took effect, the count would be a 112 and no longer 111. If you look at this with the eyes of a mathematician, you might cringe a bit because the equal sign is not an equality in the traditional sense. A count can never be equal to itself plus one. It's really an update that takes place at a point in time. Some languages actually use a different operator for assignment, not equals, but for instance, colon equals, which avoids the trap to see it as inequality. I quite like colon equals, but the majority of programming languages, including C and Java and almost all others, use equals. Scala unfortunately followed along and now it's too late to change that. So we have to live with equals. In practice, real-world objects with state are usually represented by programming language objects that have some variable members. For instance, here is a class that models a bank account. We have class BankAccount and then we have a balance, which is the current balance on the account initially zero. That balance is private so that not everybody outside the account can just fiddle with the balance and maybe add some Swiss Francs to it. That would be very convenient, but I believe the banks wouldn't like such a class. There are two methods that regulate the changes in balance, there's deposit and there's withdraw. To deposit an amount of currency, you ask, well, the amount should better be positive. You can't deposit a negative amount and if that's the case, then the balance is augmented by the given amount. The other method is withdraws or to withdraw an amount of money. Again, the amount should be positive and the amount should be less or equal than balance, so no overdraws allowed. In that case, balance equals balance minus amount, so deducted by amount and you return the balance. The result of the withdrawal method is the current balance. If the condition is not fulfilled, then you throw an error with a error message, insufficient funds. In essence, the class BankAccount defines available balance that contains the current balance of the account. The methods deposit and withdraw change that value through assignments. Note that balance is private and the BankAccount class therefore cannot be accessed from outside the class. To create bank accounts we use the usual notation for object creation. BankAccount() would create a fresh account. Here's a worksheet with bank accounts. I have defined my class as shown. I define a new bank account and I deposit 50 units initially and then withdraw 20 units and it responds that the balances now 30. I withdraw a further 20 units and it responds that the balance is now 10. I withdraw, let's say 15 units and I get an error, insufficient funds. What you've seen here is that applying the same operation account withdraw 20 from the account twice in a row produces different results. First 30 and then 10. Clearly, accounts are stateful objects. If they were stateless, that would mean that the result of withdrawals is always the same, but clearly that's not the case. So accounts have state and that we know even without looking inside account and discovering a variable there. Mutable variables can play a useful role even in purely functional programs. For instance, remember the implementation of TailLazyList or simplified variant of lazy lists. It used the lazy val to compute the tail operation. But instead of using a lazy val, we could also implement non-empty lazy lists using a mutable variable. Here's how that would be done. Here's the non-empty lazy list constructor cons, creates a lazy list whose head is as given. Then it has a variable which is private, tlopt of type, option of TailLazyList of t initialized to none. Now to take the tail of a list, it would query tlopt. If it's none, that means nobody has asked the result yet, then the result will be computed here. Tail will compute the by-name parameter stored in tlopt. Then tail would be called recursively, which would go into the first case. If someone had already evaluated the tail, then there's no need to evaluate it again. In this case, tlopt would return sum of x and we would return the result x directly. It's an interesting question to ask, according to our definition of statefulness as being history dependent, is the result of cons a stateful object? It's a tricky question and I would respond with, it depends. It's not a stateful object if the rest of the program is purely functional. To see why, let's make the argument first that it is in fact not a stateful object, that is purely functional. That argument goes as follows. It says, well, all this tlopt does, it avoids a re-computation of the tail definition here. But in a purely functional world, tail will always return the same value even if it's called several times. Clearly there's no point in evaluating tail several times. We can just use the cached value and that will not change any observation that we could make from this TailLazyList. That's true. But it's only true if the environment is purely functional. Here's a counter example where it would be false. We do a cons of some number 1 and the tail of the cons would print something. That's a side effect and return nil or rather lazy list empty, should be empty. Now we do xs.tail and we do xs.tail again. In the first execution, what you would see is an exclamation mark. It would print something and in the second execution we would see nothing. That's an output, print on, but we could turn this easily into an observable effect inside the program by essentially changing a variable instead of doing a print on. The print on was just essentially to demonstrate what goes on. The morale is that if the environment can have side effects, then the tail optimization with mutable state is not purely functional. But ironically, in a purely functional world it would be, which means there is a role for having variables essentially as caches that work very well in a purely functional architecture. That are in fact not observable in that architecture, whereas they would be observable if the architecture was not purely functional. That's something to chew on. Staying with this line of questioning, consider the following class BankAccountProxy. It's a proxy of a bank account and it simply forwards it's deposit and withdraw methods to the bank account that's given here. The question is, are instances of BankAccountProxy stateful objects? The case for no would be to say, "Well, there's not a variable insight, how can they be stateful objects?" But of course there can be stateful objects because BankAccount is a stateful object. That means the history of the deposit and withdraw methods here will mirror the histories of those methods on the virtual bank account and that means the result will depend on what happened before. By that more abstract definition, indeed, BankAccountProxy is a stateful object, even though it doesn't contain any variables itself.