 Okay, thank you for coming. This is the second talk for this session. Should be a lot easier talk, I think. Not so difficult, but actually, the earlier we were also quite okay. The content was okay. Just the math was a bit too much. Anyway, this is more programming oriented. So this is on a different kind of programming. This is about object-oriented programming. And it actually solves one of the classical problems in object-oriented programming called the expression problem. I'll tell you what is the expression problem and how this particular method solves it. And this method is very nice because it's very simple. And that's probably why it won the best paper award in the conference it was given, which is ECOP, the European Conference on Object-Oriented Programming 2012. Oh yeah, I'd also like to thank Professor Strom for allowing me to use his slides. This is slides by Professor Strom at the Joy of Coding 2014 conference. The talk was Who's Afraid of Object Algebra. They essentially also talk about the same paper, but here's really nice slides. So I thought I'd just reuse it instead of redoing the work. This was the original cover slide of the talk. Okay, so the idea here in general talk about accessibility. So we're looking at we have some existing module or classes or objects. This is object-oriented. This is setically typed. The object orientation is the feature that we use in this particular solution, but this problem, this expression problem occurs in any statically typed language. So the classic example is you have some, the toy example we have is you have some language with additions and you have some code written for that. And now you want to extend this language with multiplication. And you don't want to change any of your existing code. You just want to write like new code to add in the addition feature and reuse all the existing implementation for the language with addition. How do we do that? So that's the question. This is what it looks like sort of. So you have the syntax like one plus two and then the classical way of doing it in object-oriented languages is you define you know interface say expression exp and then you define subclasses for each of the parts of the expression. So you have the literal, the one and the two. We call the class lit and then you have a class represent the addition operation class add. This is a very classical way of doing it. And then you might convert that syntax one plus two into the abstract syntax, which is the new add parentheses, new literal one, new literal two and so on. Okay. So this is the example problem we will look at. And generally what we want to do is there are two classes of things. So one on the left hand side we have the variants, which are the different kinds of components of this simple mini language, right? You have add, literal and multiplication. And on the other hand you have different operations, which is what you want to do with this structure that you've constructed. So maybe you want to eval, like you want to print out the value or you want to print means you want to like show the string representation of the expression. Like so just like show the string one plus two instead of show the value three. And you can do many other things like you can run a type checker, you can run different things over the tree of expressions, right? So here's an example of eval, right? So if you run eval over the tree, you get the value three. If you run the print operation, you get the string one plus two, right? So let's talk about, okay, let's talk about this. Let's talk about this first. So okay, the expression problem was coined by Philip Wadler in an email to the Haskell mailing list, I think. So it is a problem with technically typed languages. I think dynamic languages have no issues with this. So the idea is you want to add new cases, which is new variants, like the multiplication. And then you want to also add new operations, like maybe, you know, instead of eval, you have print and type check and so on. So you have these two ways of extending the problem, right? And you want to do that by writing new code without changing existing code. And then obviously that means without recompiling because you didn't change them. And as well as you still have the static type safety. So all the types work correctly. This is called the expression problem. Okay. And then, so you have different languages. And actually the examples languages now was shown in dot. So in particular for all languages, they work very well in adding new variants. So that's what it means here, right? So all languages like Java, C sharp and so on work very well adding new variants because they are like new, like subclass new implementations of your interface, like new class multiplication, right? And so on. But they're not so well in adding new operations because you can measure operations will be like methods in your the classes, right? Like your ad class, your multiplication class. So to do another like operation like print, you're going to add a print method to all these classes. So that requires actually need to change all the the classes. Yeah, you can put code. So that's not that doesn't solve that doesn't satisfy the expression problem. The other way around for functional programming languages like record, which is not here. But anyway, so Haskell, ML, F sharp, OCaml and so on. It's easier to add new functions like because you usually pattern match over the objects. And you can just define new new functions like you can do you find eval function, divide a print function, define a define a type check function or whatever it is. It's easier to add new functions, but harder to add new types or variants, right? Because we add a new change all your existing functions to have a new case to handle the new variant. So it seems like there's some trade offs like if you use one and the other, right? You can extend in one axis, but not the other. So the question is can we extend in both axes in a very simple method? So that's what we're going to do in this particular paper. Okay, which is called object algebras. It just has a very complicated name, but it's actually a very simple thing. So you can think of it as a design pattern, you know, a way to structure your classes using something called abstract algebra, explain what it is, and that solves the expression problem. And the interesting bit about this solution is not the first solution, but it's a solution that uses very little advanced features of languages. So you see as I tell you the solution. Okay, yeah. So let's look at, okay, so this again is a classical example of how you do it in OO language, right? You define a class for each of your variants. So, okay, I sort of went through this part. Yeah, never mind. Okay, yeah. So OO does it the horizontal way, right? You define all the variants, but you can't do the other part. And then one way we can also do it with the operation is something called the visitor pattern, but I guess I won't dwell too much into that, not really a crucial part of the paper. But you can do like the FP style, you can call visitor pattern, if you know what that means. If not, never mind. You can also do the functional programming style in OO languages with this visitor design pattern. So it has the opposite problem as I said. It doesn't work well for adding new variants. Okay, so let's come to the solution now. So this is the interesting bit. How do we solve it? And what is the inside actually? And this is the paper, right? So what is the inside? So again, let's look at the original solution. I mean the original, the classical way of doing it with OO, right? You will have like print and eval methods in your object, right? And then if you want to do another like method like type check, for example, then you got to put another add a type check method to all your objects, right? So it seems like our objects are getting more and more fat. So the solution turns out to be let's make custom design objects. So instead of one object with many methods, one method for each of the operations we want to perform, we will use a sort of custom object or single purpose objects as it says here on the slide. So for the problem of printing, we will just have one object with the print method. And for the problem of doing eval, we have another object with the eval method. So separate objects instead of mashing it all into one thing. So sort of like a factoring, right? We break it into the parts because actually print and eval are sort of separate. They don't really like interact with one another, right? They're actually quite independent code. So we should perhaps do them separately instead of mashing them together. If we do that, then it turns out we can actually do it, can actually solve the expression problem. So let's see how we're going to do that. So as I said, we need to have a different object each time, right? So for print, we have an object that knows how to print and for eval, we have a different object that knows how to eval. So they're not the same thing. So that means we cannot construct the objects directly like new something because then that will fix the object. So we need to change the object depending on what we want to do. So for that, this is also somewhat familiar pattern. It's called the factory pattern, right? An abstract factory pattern in this case actually, which means instead of calling the constructors of the object, we use a method. So in this case, the lit method returns you the literal object and the add method returns you the add node or add object, right? And we just need one more step, which is we don't actually know the type because the type will be different because in one case, the object can know how to print and in another case, object knows how to eval, right? So actually the type is going to be different for the two objects. So we cannot fix the type ahead of time, which is here exp. So we just need to perform one more level of abstraction. We just put the type into the generics. So we just, we don't know what type because we don't know what we're going to do. So we just say it's the type E, some type which do something, maybe print, maybe eval, maybe type check, whatever. So we'll have this, now we call it the generic factory because it's a factory to produce something of type E, which we don't know what it is until we need it, right? Does that make sense? Okay, so actually this is all we need, kind of, more or less. Okay, let's see. So where is the link with algebra, right? Turns out way back in the study of ADTs, abstract data types, in a sort of formal mathematical study, there's this notion of algebraic specification. This is the thing on top. So an algebraic specification of a data type has things like a signature, it's a little ML-ish, I guess. You have the signature, you have this generic variable E and then you define the operations and so on. These are the operations of your ADT, I guess, in that particular paper. So if you look at that, that's actually very similar to the thing below, sort of factory methods, the lit and add returns you objects. They don't actually do anything, they just sort of return your object that has the method. So that's why they call it object algebras. Okay, so let's actually see an example first. So before we get into the last part, let's hope this doesn't mess up the recording. But anyway, so let's see an example of implementing that type. So we could define a type, okay, here the name a little bit different, but the thing of VEL as lit in the presentation. So just now, you just saw how we defined the generic factory, right? But we actually still need to implement it to actually write the code that does the plus and E VEL and so on. So this is how it will look like, right? So you would say it's of some type E VEL, but the type E VEL means it has a function called E VEL. That's really all it means. That is the interface, which says that there's one function called E VEL. And so this is the factory method. So this VEL here is the factory method, right? It returns a new object of type E VEL. This is Java. So this is an anonymous in a class, anonymous object that has a single method called E VEL, which just returns the thing because this is the literal, right? The value. So the evaluation of the literal is just like the number. And then this is the implementation of the add sort of factory method that returns you an object of type E VEL, which has this particular implementation, right? So it evaluates left hand side and then the right hand side and then adds it together. Does that make sense? See? Simple, right? The code is not complicated, I hope. So you can see what we need here. So we actually need two things. We need generics and we need, later on we'll see actually, well, we need subtyping actually. But here we need, here with implementing interface, which is also quite a common operation. And you also do this with, I guess, C. You don't have interfaces, fine. You can use like an abstract class or something. Still works fine. Okay. So now let's try and do the two ways of adding things. You can add, so one way is to add a new variant, which is, let's say, add a multiplication note in the expression tree. Okay. Let's look at, oh, sorry. Let me show you the print first. Yeah. So this is how print would look like if I want to implement the print part of it. So I want to print the value one plus two instead of print, print number three. So it's pretty similar, except we define an interface called print that basically means it has a function called print. Pretty straightforward. And then, you know, you just implement that particular method print inside the, in the object that you return. And same for the add, right? Okay. So, so here we're going to, here's the, now here's the interesting, here's the extension, extension bit, right? So far we're just using it to encode the standard part of the problem with literals and adds. No one extended with multiplication. So in, here in object algebra is actually quite easy. So you define a new generic factory, if you recall, this expression algebra x is a generic factory. So we extend this. So it means it has all the methods of the earlier factory, which is let val in this, in the code is val and add. And we extend it with one more method called mal, which represents multiplication. This is adding a variant. This is the left-hand side, right? So again, mal is like add. It has left-hand side, right-hand side, and then the result, which is, again, this unknown x thing. So, okay, so this is fine. And now we need to update the two methods, right? We have the eval and print. So how do we do that? So in quite a similar way actually. So we just extend the, so we're going to do evaluation of the new language with multiplication, right? The interesting part here is you can reuse all the other things we did in front. We just extend the exp eval, which already defined the methods for val and add. We just need to add in the case for the new variant, which was mal. That's all we need to do, actually. So we didn't have to change any code at all, right? If you notice, we only extended existing classes. So this is particularly more important when you're writing libraries, for example. Because we're writing all your own code, then you can just break open your class and just change the methods, right? But if this is some library that you're giving people, then it's easier for them to just extend it with their own additional things instead of having to edit the library code. Okay, so this is eval. I think there's one more example, which is print. So print will sort of the same way. We'll just write the minimum we need to do, right? Which is just to tell it how to handle the case for mal. Because I think other cases we extend from exp print, right? So that's pretty much it, actually. Let's say this is simple. It's not supposed to be complicated. Okay, so we'll talk about this. So the syntax here is a bit different because this is Dart. But it shows that it works for works in Dart. So not just in Java, it works in Dart and probably in C-sharp and bunch of other things. Because it doesn't use anything at all, right? It uses only generics and subtyping. So subtyping, most languages have, most object-oriented languages have subtyping. Most modern languages have generics, like even though Java retrofitted generics in after 1.5 or something. So yep, this is like a recap. So object algebras, what are object algebras? So we defined a generic factory interface. And then to define the implementations of the various operations, we create the implementation of the factory, like the exp-alg. So to add new variants, we extend the interface of the factory. So we can extend it with the mal operation. I mean, just define what it means, right? mal x lhs rhs. And to implement it, we just, we can implement the interface, but we can reuse the previous implementation by extending it by inheritance. So this is implementation inheritance. This is sort of a diagram that shows you the relationship between all the various classes. So the left-hand side, you see the two algebras. Alg is algebra. So the top, we have the expression algebra. So if only the value and add, then the multiplication algebra is like a subtype, I guess. It's an extension. It extends. The hollow arrow is extends. And the dotted arrow is like implements. So we have two different operations, print and eval, that implements the algebra. And then you have the, so when we add the new type, we can create the two new print mal and eval mal by subtyping from the earlier implementation. So we don't have to write any additional, like repeat any code. Okay. And sort of this is a rearranged version of the diagram. So here on the vertical axis, you have the different variants. So the variance means we add new type of node operations. You can just easily add more, just by defining more of these concrete factories that creates the objects. So the special thing if you remember, again, the key trick is that we create the object on the fly as we need. So we create the object with just the method that we want. So if you want to do print, we create an object with just the print method. If you want to do eval, we create an object with just the eval method. So this scales because then you can have objects with different kinds of methods. Okay. And in summary, this is a very simple solution to the expression problem. So earlier solutions actually require other things like bounds on generic. So some languages support bounds, you can have upper and lower bounds on your generic parameter. Java supports that thing can say e extends some type t or e is a super or some type t. So that is a little bit more complicated. The other features that some other solutions use is wild cards. So you have, you can have things like question mark in the type, like any type in the generic. That's also a little bit more difficult to use. So this particular solution doesn't have any of these features. It uses a concrete type. So we always say it's an expression algebra of type e or x. We don't have to say e extends some other thing or using more complicated type features. We just need, we need just simple generics. It's good enough. Yeah. For any generics as in like templates in C++ is good enough actually for this purpose because C++ doesn't yet support the idea of bounds, which it may I think in later versions. Okay. And so we use object algebra because we solved the expression problem. Okay. That's all. Yes. Question. So there's a problem. Yeah. What happened when you extended in parallel and then you try to join them in, then you need multiple imperatives. Good question. What do you mean by join them in? You start with the ad, right? Yeah. So you have a mouth that extends from ad. Yes. And then let's say you have another one division that also extend from ad instead of extend from mouth. And then now you want to, you want something that support both mouth and vision. Ah, okay. So let me see. They are, they are, they have a, it's like a diamond, the diamond inheritance. So there's another, there's another example actually in the paper they discuss this. They didn't discuss this in the talk. Another way they, they discuss in the paper is like this. So maybe I'm more, because that's a bit a little bit weird example. So another example, maybe you have a, you have like integer expressions and you have Boolean expressions. They're sort of different realms. Like Boolean will have like n and different operations, right? And then, then you want to combine the two algebras to have a language that have both integers and Booleans, for example. Yeah. So that may be more, slightly more realistic scenario. So how would you do that? So in particular in Java, you can't really do it without rewriting code because you cannot have, there's no multiple inheritance, so to speak. In Java specifically, it's a single, so for that you can actually solve it with languages with traits or mixins like Scala and maybe, maybe Dart, I don't know. But anyway, so not specifically in Scala, in Java it cannot, it cannot solve that particular case. So you could do it with composition as you, as you normally would. So you can, you can have a, you can have an int-bool language, int-bool algebra. And in Java, I guess you would have to have two like local variables like do it with composition. I think that's the cleanest way, right? So you have internally as two local factories. One is the int-algebra factory. One is the bool algebra factory. And then for each of the methods, it will sort of delegate to the appropriate internal factory. So you get an int-bool factory. Yeah. But yeah, you have to sort of rewrite the, the methods to delegate because there's no way to delegate automatically, right? But some languages say, you can say, these methods will use this, like object. This is super fast. Yeah, these are like members, right? So you have members of this, this int-bool factory, then you can just use it. But in Java, I guess you have to say like, you have to say explicitly, because there's no sort of delegation feature. Yeah. But you can still combine it actually, yeah. Yeah, you need to delegate. I think in practice, this would come out a lot more often because new features can be added in parallel. People can develop different kind of language features separately and then they want to join back. So if you use inheritance, they could have like multiple branches. Yeah. That's true. Inheritance here mainly is for the purpose of reusing the, the code. So if you have language with delegates, you could technically also use delegation. You don't have to use inheritance. It's just an example here in Java, we can only use inheritance if you don't want to rewrite the methods. Yeah. Other questions? It's interesting because when you're working, you, you end up coming, coming up with like half big solution of something similar because the problem was never formalized, like in my mind, I never knew this was one of my strengths. It's like, yeah, but I want to do this, but I want to do this. Right. So annoying. And then you come up with some strange solution for it. Now you realize actually, this would have been a much nicer and cleaner effect if you had known about this problem and this solution. This is quite, quite a bit of a leap of insight in the sense that you cannot bake your objects in, you cannot like new like construct the objects. You have to use another function to construct it. So there's this additional level of indirection like here we have to call all these methods. So for example, if you're really writing a language, your parser will have to take in as input the factory object and use that to instantiate the stamp out of the nodes. Yeah. But then the nodes can only do one thing. So if you need another kind of node, you have to put it into the parser again to stamp create a different tree. So these examples are for like, like a trees and stuff. It doesn't have to be, it's really anything where you have variants and operations. Doesn't have to be like language trees or whatever. It's just that this happened to be the example from the expression problem paper. In the functional languages, I think there's also another solution is which is open some type. I think it's a demo where you can have an open and some type that you add new variants later on. Yes, that's also possible. Open classes. In general, there's some languages with open classes. So I think that's similar, right? Where you can add variants to the some type. Yeah, that's true. I guess here they're talking about the fact that if you, so in that case, the type is still the, there's still only one type, right? I guess when you extend the type, does it become like a separate type or is it still the same type? It's a bit like, it becomes a bit like object oriented because then you have to add a default case for a handling unknown type, unknown variant. So then every time you measure a variant value, you have to always have a default case. A default case, okay. Yeah, that could work too actually. It's just that that feature is probably not available in most object oriented languages. Yeah. Another new language features probably can help is also like low polymorphism. Yes, you can define a record and then you add in a new record and then you can combine these type of records of factory functions. Yeah, I mean, this is not the only solution as I said. So I mean, I think that the fact about this one is that it's just, it's simple enough that it works in most like existing languages, mainstream languages. It doesn't need any language changes. So that's the beauty of this particular solution, I guess. Yeah. Thank you very much. All right, thank you. Next meet up in a month. If we have people, thanks for both of you for doing necromancy and reviving the meetup. And you can always blame me for being the lazy person to not border, you know. Advertising this one, you want to point out to me. Isn't that a big like internet meeting? Yeah, ITF. Maybe you can find someone to present. Yeah, can maybe. But that one is like second week. Sorry, there's some interesting people who want to talk. We can work stuff out. I don't know. I don't know if people think that preparing a talk is a big hassle. That's kind of a cheap trick. If you notice that I've been using, you don't use your own slides. You find someone who has given a really good talk and you ask them to use their slides. Then that kind of gives you like 90% of the way. They just need to do 10%. That's usually quite doable, actually. The hard part is finding good slides. It's very hard to find good slides. Still, this is all the problem. It's still back in the same thing. But at least there's an option. There's a sort of a cheat way out. No, but it's a paper. Usually somebody presented it the first time. No, papers are different. But likely, because generally people will write a paper, then talk about it at a conference, something similar, whatever. Yeah, a lot of the conference things are now online or whatever. Yeah, now it's very good, actually. Now it's very advanced. Try HM's PhD. Secret. Nobody knows, ever. No, definitely not on the interwebs. You now have video, now they have slides, whatever. It's so many. Have a look at Michael, over here, please. Thank you, sir. See, it's like Michael Chang is more, you know...