 All right. So, let's get started. I am Hisham. I work at Kong and I'm also the maintainer of Lurox, the package manager for the Lua programming language. I've been involved with Lua since 2005 or so. So, it's been working with Lua for a long time. And I'm here to talk about minimalism versus types. And the long journey about the hard relationship between like a minimalistic language like Lua and the desire for types. So, minimalism. Well, I love minimalism, as all of us here in this room probably do. And once someone asked me like, what do I like the most about programming with Lua? And the answer that I gave like right off the bat was that, well, Lua fits in my head. Like I feel like I know the entire language, right? It's like the whole reference manual is like this one web page that you can read top to bottom. And like there's no like corners of the language that I feel that I don't know. And it's just like in this, it's a very gratifying since the sensation like being able to work in a language like that. Like as opposed to huge languages where there's always like some kind of construct or part of the standard library that you have never touched. So, like this is a classic example of like huge language versus like small language. And like for reference, like the entire Lua reference manual is about the size of JavaScript, the good parts. So, the size of the languages and the size of their good and bad parts also kind of match, right? Actually, the last like JavaScript, good to the right. Hopefully, something like that. Well, it's actually older than JavaScript, but in many senses it's similar. And some people who are thinking of the other side of JavaScript, they get surprised and know they're nothing alike. But if you focus on the good parts of JavaScript, then they're surprisingly alike. So, types. I also love types. And one thing that I like to say is that programming with types feels like pair programming with the computer like you program a little bit and then the compiler comes and say, well, you missed like you made a typo here something and something like that or you cannot really pass this to that and all of that. So, you get this nice feedback loop that's different than running the program and seeing if it crashes, right? And so, this is like, this is my interest in types from a very practical perspective as a practitioner or as a programmer, like and not just a theoretical, like as a programming language, academic sort of interest. So, before we dive into types, just let's just get our terminology on the same page. Like when people often talk about typed languages and untyped languages and so, the more accurate terminology would be like, when you talk about untyped, you mean no types at all. So, that would be like assembly, everything's a byte, right? And those are not usually like the types of languages that like the kinds of languages that we care. And for all the other ones, like there are types, like types exist. So, string and number are different things. Automatic coercions can make this a bit confusing. So, I said, oh no, it's not typed because I can do like string one plus two and I get a number. So, now it's actually like it's just doing an implicit conversion, there are actually different things. Like in Brad's presentation, he mentioned that all originally in TCL, everything was really a string and then now everything is representable string, even though there really are different things. So, like modern TCL has types, like all of the other model languages do. So, people in the theory field, they say like you shouldn't even talk about untyped. You should just talk about untyped because when you don't have types, you really have one type, like the type of everything. So, the distinction that we usually care when we're talking about this language is typed or not. Like when we informally say that is that whether it's dynamically typed or statically typed. So, dynamically typed in a nutshell means that values have types, but variables don't. So, you can move values that have types around and they fit any variable. So, languages that fall into this category are like Lua, Scheme, Erlang, Python, Ruby, and so on. All of those typical, the ones that we call scripting languages and some that we don't, but that's it. And statically typed means that values have types and variables also have types. So, if you have an integer and you want to put in this variable, this variable better be of the integer type because otherwise it will not accept it. So, like C, Java, Go, C sharp, Rust, Haskell, like all of these other are static checker and a step that you run before, like runtime that tells you if your types are okay. So, for the purpose of the differentiation, we will totally avoid these terms like strongly typed or weakly typed because they're very confusing and like everyone seems to have like a different definition of what those mean. And the better distinction is really dynamic or static. So, this is what we care about. But we also care about minimalism and apparently all of our favorite minimalistic languages all fall in the first group. Like, there's Lua and Scheme and like all the ones, TCL also there. So, what gives? Like, what happens when we put minimalism and types together, right? So, let me go through a brief history of the efforts for typing Lua. So, back in Lua Workshop 2013, Fabian Flutua presented title lock, which was based on meta Lua, his Lua Metaprogramming Library, where he attempted to do like gradual typing of Lua programs. You could partially add type annotations that would verify them and all of that. In his presentation, like the main point of his presentation was that we all left like scared of the prospects of how hard that problem was. Because he started like showing like, oh, in the simple cases, this is in this work and then it starts getting messier and messier and messier. Because once you start to capture the way that Lua programmers deal with their data structures, he started to have to apply heuristics and things like that. So, he start scratch your head and say, well, wait, my type checker is going to be running heuristics on the code, right? So, because when you think of a type checker, you kind of want some certainty and in the end, it seems to be like a really tough problem. Nevertheless, tough problems is what research is made of. So, around that time, Andre Maidl was working with Lua in types. Two years after that, he presented his PhD dissertation on that was called typed Lua, an optional type system for Lua. So, he worked hard on many of those complicated problems and he came up with a super complicated type system that had many pages full of little Greek letters and the thesis as he tried to make sense of the whole thing. He made an implementation that's on GitHub. That implementation is a nice prototype of all those ideas. But really, it's not ready for prime time in a sense that you can't really feed real world programs in it and try to use it as a day-to-day tool. Because the type checker is just too strict, it complains about lots of things that you as a little programmer said, no, this is right, but the type checker just doesn't understand and it is a super complicated one. So, I got involved. Back then, I was doing my own PhD at the lab, like in a completely unrelated subject, but I got along with the people there. So, we decided to start kind of a side project on that. Two years later, around 2017, we started a project called Titan that would be a statically typed language that will be like Lua-like, but not try to type Lua, but create a new language that will be set like the type that will be somewhat like Lua and designed to interact with Lua. This is still an ongoing project, and it shows that we clearly at that point, we gave up on trying to type Lua. I said, let's just do something else. Really, Titan tries to fit more as when you're programming in that part C, part Lua like embedded language type of thing, Titan would be more suitable for replacing the C parts rather than the Lua parts. So, it's not really the same thing. At the same time, there's like super hard research questions on how to go about this, and like some of us were approaching it from a very practical standpoint, some of us were approaching from a theoretical standpoint. So, at one point, the project split off and like the research branch of it is the Pauline project in which they're really going like data structure by data structure from first principles and doing the research on that. So, yet here we are, 2019 and we still don't have a type checker for Lua. We don't have a way of like after that many years and so many people like putting efforts on all that. We don't have a way to use Lua and types together. So, what gives? Why is it so hard? So, I did some soul searching and thinking about the whole thing and I'm going to share like my thoughts about it. So, our first stab at that question, like when you think about it, like and we are here talking about minimalistic languages and I start talking about types, types, types and how everything's complicated, and from your own history experience dealing with typed languages and you think about like, I don't know, Haskell or Rust or C++. Languages that has huge complicated type systems, you start thinking, oh, they ended up being complicated languages because the types mess up everything with the minimalism. Like once you add the types and the whole enchilada with it, the language is no more minimalistic. So, maybe like, so, types make our tiny languages complicated? Like is that the problem? My conclusion is that the problem is kind of the opposite and this can be a little surprising. But, when we think about like our little dynamically typed languages like Lua and Scheme and like your favorite one, you might realize after you look at it for a while that they actually have huge type systems and very complicated type systems. And you go like, what? Yes, so if you think about the type system as being, well, the set of rules that describe what are the valid interaction of values in correct programs, which are the things that a type checker checks, right? So, essentially the type checker for those languages, it's in your head, right? You are the type checker. But, if you take like the C language and it has a type checker implemented inside GCC, you can look at the source code and you can see this is a type checker and this is what it does. Those are the rules, right? So let's open our heads and look at the type checkers that we have inside our heads for Lua. What are the rules in there? You know, like how complicated? Like if you were to write it in Greek letters in a PhD thesis, what would that type system look like for Lua codes that we actually write nowadays with our tiny Lua language that fits in a, you know, in a 200K guitar ball, you know? So, if you are the type checker, what type system are you checking? You know, because this is the kind of work you do. Like you do, like we have multiple returns in Lua, you do, oh, get coordinates for those two values and you realize like you give a type error to yourself and say, oh, I can do that because yesterday I changed that function from returning two things to returning a table. So that line on the top is not gonna work. This is the kind of doing that you're doing in your head. That's why I mean by you are the type checker, right? So what are you checking? What are those rules? Well, now we have to go to the state of the art of type systems, right? Because I was talking about dynamically typed languages. I was talking about statically typed languages but within the realm of statically typed languages there are dependently typed languages. Dependently typed languages is a new, like in the practical sense, category of languages in which values have types, variables have types but types have values and types have types, right? And since, well, since types have values and values have types, right? You get into an endless infinite tower of complexity there. And now there's a few examples of languages out there like Idris, Agda, there are not that many yet. Like people always say like the same three and the third one is actually like a proof assistant. Like, you know, the cock from Nghia, right? So really, but this is the kind of type system that you have in your head when you're working with a dynamically typed language, right? You have like a nice function F, A and B. What are the types of A and B? You know, A is an integer and B is, well, if A is less than 256, then B is a string, otherwise B is an array of string. You know, when we have, when we're programming with dynamically typed languages we do that kind of stuff all the time without like even realizing that we are creating these complex types that have like the definition of the type has a dependency. That's why it's called dependent types, right? On another value, right? So just pause for a second and imagine like how hard would be for you to write a type checker that would be able to check that, you know? Like you would have to go through the flow of every like possible path that leads to the first argument and determine that the integer that was evaluated could possibly ever be like less or more than 256. And then if you got a table, you have to prove that, you know? But isn't this just probably created because this is a very bad IPI, so. Yes, but if, but once we have a dynamic language you do come up with those things because essentially the dynamically typed language since it imposed no restrictions it lets you think those thoughts, right? So, but when you're doing the work in your head like it's kind of like it's not that hard you don't actually do like the flow analysis of the entire program in your head every time because suppose you have those variables here, red, green, and blue in there and you know they're all integers, right? You can know that, oh, those. If you see something like this and you know like, okay, so these are RGB components they go from zero to 255 and then I'm passing an RGB component there with an array and that's not gonna work because I expect like those numbers to be within the range and so I need to be strings and not to raise so there's probably an error here, right? But if the type checker had the information that read it's only ever between zero to 255 you had to specify that in the type, right? Or then the type checker would have an easier job we would be actually able to do that, right? But once you have the idea of a type system that has like all of arithmetic in it, right? And by I mean like a type system that encompasses our arithmetics it means like by the Curry-Howard correspondence it means like every type system corresponds to a kind of logic, right? So like first order logic, second order logic, you know and those things, right? So and by the way, since the 50s we know that arithmetics has proven undecidable in logic so if you can have a type checker that knows all of arithmetic. So yeah, so we kind of do those things all the time when we're programming here. Like for example, you do something like this like load values into a table you give them okay and an error. If not okay, then well, the type of error is like is dependent on the type of okay. Like if it's a string, if okay is false, right? Or if it's nil, right? And then what's the type of T? You know, when you get there T of one, right? Well, it might have failed in between and all those kinds of things like the flow analysis could get really complicated. And when you get to that like in the case like Lua where the table is the only structured type. So when we say like everything's a table like apart from the primitives, you know strings and integers and all that it means that a table is anything. So a table can be an array, it can be a dictionary, can be a struct, can be an object, it can be a dictionary mapping objects to strings or arrays depending on whether the field of the key object is true or false, you know and without realizing you start creating the super complex types, you know you start creating those super complex structures that if you were to type them those would be the types that they would have to have. So it comes to a matter of expressiveness, right? And when we mean like expressiveness in a programming language like how expressible it is I don't mean like really what language can express because you know kind of like touring completeness you know they're all the same blah, blah, blah but really it's like how can you express it, right? So in that sense the dynamically typed language is super expressive but it's super expressed in the same way that a blank sheet of paper is now the paper accepts everything, you know the dynamically typed language accepts everything and well it goes boom and you know if you do something wrong at runtime. On the other hand the type checker works both for good like oh thank you for catching my silly typo and for bad like and you know like I know that this use of the variable is safe here why are you complaining about this, right? So essentially the expressiveness is like the fuel of a language like regardless of the look, right? So in Lua you can have something like this like a table that stores like name fields like and also servants and array like both of them, right? If I take like if I do like a small transpiler that like took all of the keywords from Java and turn them into Lua like it was it would still feel like Lua, all right. So okay so I'm just gonna jump ahead and just going. So here for the final section like how so in the end like how much of the language do you change? Like do you make this illegal because like it's either a map or an array, right? Cause you could still represent something like this like in Java, right? You just make an object that has like the name field and then a list you put one inside the other so it's like you have to think those thoughts like in a different way, right? So the final point is if you wanna make it feel like Lua then the type checker is super complex. You wanna feel like 100% like Lua then the type checker is impossible, right? Because you end up with undecidable things. And if you want to actually finish writing your type checker you have to make cuts somewhere but not in the word somewhere. So two options on where to make your cuts. Well first you can cut on program expressiveness. As I said like you don't allow them to mix an array and a table and say like oh in my typed version you have to do something like that. You know items, right? Or and maybe say well I cannot make something that's like sometimes a nil, sometimes a string and I can instead of doing return x and y and return nil and error in the same function if I want to use those two things in the same function then we have to do return x and y which is always like an integer or an optional integer and the third one would be like the next free available entry would have to be like the error message. Like those are simple, those ones are fixable, right? But I'm just giving them as simple examples, you know? Otherwise you can cut on the correctness of the type checker. So you go from like the promise that every program that the type checker accepts has correct types to something like oh if I complain then it's probably like wrong but if I don't complain I give you no guarantee. And still it's hard because you made the equivalent logic of your type checker it's an unsound logic and once you add unsound logic you can start like proving absurd things and when you go back to the type checker it means that it will behave in very weird ways if you're not careful and probably even if you are. So the more sophisticated type system the deeper you are in research territory. Everyone has felt like whoever tried to deal with that ended up doing with this. So is that all lost? Like in the final minutes here? Well, TypeScript has proven to be like a successful attempt in the industry when doing that. And essentially their choice was to go for usability above all else. It means that the type system is intentionally unsound and this is not just a technical thing. If you go there to their bug tracker there's lots of bugs that are closed by design, by design, by design it's not meant to detect that failure. So what about Lula? I probably have like 30 seconds and just to give a glimpse of hope well I've been working on exploring this design space and playing with it so I decided to try to write a minimalistic type checker in Lula but just like what's the minimum set of features so that it could type check itself? That would be like enough to be like a real program. And not there yet? Well, when I try to run it like on itself it currently fails with 384 type errors. A week ago it was a lot more so that's progress. The thing is that once you start fixing it like you fix one thing that fixes 100 errors but now it's like Achilles and the turtle. But yeah, the idea is to do something a little alike. It's here because even if then though it's not finished it wouldn't be false then I'll talk about code and it's not a source. So in closing, yeah, the story will continue and thank you.