[00:00.000 --> 00:29.600] Hi, everyone. So, this is Frank van Bever with Lua for the lazy C developer. [00:29.600 --> 00:42.120] Hi, I'm Frank van Bever, and I'm here to talk to you today about the Lua programming language [00:42.120 --> 00:48.200] and specifically for lazy C developers. So, first of all, who am I? Frank, I work for a [00:48.200 --> 00:55.120] company called Mind, free and open source. Well, there's consultancy, specialized in free and [00:55.120 --> 01:00.480] open source software for embedded systems. If you're the kind of person who enjoys the [01:00.480 --> 01:04.680] referencing pointers and you're looking for a job, check out our website or come to talk to me [01:04.680 --> 01:12.640] in the hallway after the presentation. So, with that out of the way, why am I here? I am here [01:12.640 --> 01:19.720] to talk to you about being a virtuous software developer. So, the man on the photo is Larry Wall. [01:19.720 --> 01:27.880] He's mostly known for being the creator of the Pearl programming language, but he also coined [01:27.880 --> 01:34.840] these three virtues of a great software developer. These virtues are laziness, impatience and hubris. [01:34.840 --> 01:43.800] I want to focus on the laziness virtue specifically today. And so, he defines laziness as the quality [01:43.800 --> 01:49.520] that makes you go to great efforts to reduce overall energy expenditure. It makes you write [01:49.520 --> 01:54.480] labor-saving programs that other people will find useful and document what you wrote so [01:54.480 --> 02:02.680] that you don't have to answer so many questions about it. Now, in my day job, I'm mostly a C [02:02.680 --> 02:06.880] developer and, well, if you have any experience with that, you know that there can be quite [02:06.880 --> 02:14.360] some energy expenditure involved in doing that. So, introducing the Lua programming language, [02:14.360 --> 02:22.400] quick introduction. It's a programming language. It's multi-paradigm. You can program in both an [02:22.400 --> 02:29.640] object-oriented style. It uses prototype inheritance. So, for people used to Java or C++ might seem [02:29.640 --> 02:36.800] a bit strange. It has the same inheritance model as JavaScript. It actually has quite a bit of [02:36.800 --> 02:43.600] resemblance to JavaScript in some ways. They were both created around the same time. Big [02:43.600 --> 02:54.320] change from C is that Lua is dynamically typed compared to C's static week typing. So, you can [02:54.320 --> 03:00.800] just declare a variable. You don't have to specify the type. You don't need to care about it. Lua is [03:00.800 --> 03:07.200] small. That can be interpreted in many ways. Lua installation that I have on my machine is about [03:07.200 --> 03:15.480] 250 kilobytes. So, it's really perfect for embedded systems where often you're constrained. But it's [03:15.480 --> 03:21.280] also small in the sense that it has, like, language itself. It's like a small set of meta [03:21.280 --> 03:27.640] features that you can use to then build whatever it is that you need. And one example of that, [03:27.640 --> 03:33.640] for example, is that there's only one data structure, a table, which is like a map or a [03:33.640 --> 03:40.040] Python dictionary. And by basically constraining the behavior of this table, you can get all [03:40.040 --> 03:48.200] kinds, well, you can basically build all kinds of other data structures. So, yeah, basically it [03:48.200 --> 03:54.280] being a small language, C developers should feel right at home. Another big difference is Lua is [03:54.280 --> 04:05.600] garbage collected compared to having to do manual management in C. Lua will basically take care of [04:05.600 --> 04:14.240] that for you. And most importantly, for a C developer, Lua is actually also a C library. What [04:14.240 --> 04:21.960] does that mean? Well, on the left, you have Hello World in Lua syntax. And this program can just [04:21.960 --> 04:30.760] as well be expressed using Lua C API, which you can see, well, yeah, my left, left, right. So, [04:30.760 --> 04:39.720] for you, also on the left side, the Lua C API, these two are equivalent. So, how does this, [04:39.720 --> 04:46.680] well, so how does this work? Well, Lua has as a stated design goal that it should be both an [04:46.680 --> 04:53.840] extension language, meaning that you can call Lua from C, so extend your C application by using [04:53.840 --> 05:01.760] Lua, as well as an extensible language, meaning that you can call into your C code from your Lua [05:01.760 --> 05:12.640] application. And the way it does this is by using a stack. So, this stack nearly, so the C API, [05:12.640 --> 05:19.000] everything it does is manipulate this specific stack. And this fixes two important impedance [05:19.000 --> 05:24.480] mismatches. So, like I mentioned before, first thing that it fixes for you is the static typing [05:24.480 --> 05:30.880] versus the dynamic typing. If we had to map the internal state of these Lua, of all the internal [05:30.880 --> 05:39.680] Lua types to C types, well, a knee jerk reaction would be union types structs. But that's a row [05:39.680 --> 05:45.120] that quickly leads to insanity. By using this stack as like a clear boundary line between the two, [05:45.120 --> 05:52.720] it's easy to translate your Lua variables into, well, Lua variables into C variables and vice [05:52.720 --> 05:59.720] versa. Second thing that it fixes for you, the second impedance mismatch is this manual memory [05:59.720 --> 06:06.480] management that you need to do in C while Lua is garbage collected. By popping, well, by pushing [06:06.480 --> 06:14.040] and popping from the stack, it is clear when the handover happens of memory from one, from one [06:14.040 --> 06:27.000] side to the, well, from the C side to Lua and vice versa. So, where might it make sense to use Lua? [06:27.000 --> 06:34.520] So, well, as you can imagine, using dynamically typed scripting language that is garbage collection [06:34.520 --> 06:41.960] comes with a performance hit. So, you need to keep that in mind. But so, for some cases where it [06:41.960 --> 06:50.960] might be useful is taking care of tedious stuff that runs sporadically. So, especially, yeah, [06:50.960 --> 06:57.720] there's no better way to get me to run to the coffee machine in a grumpy mood than having to [06:57.720 --> 07:05.200] do a lot of string manipulations in C, like an edible. And so, stuff like that, especially config [07:05.200 --> 07:11.400] files, for example, it makes, it can make sense to say, okay, you know what, we're going to call out [07:11.400 --> 07:17.480] to Lua, we get our config, we put it in a C struct, and then from there, we can go on with our [07:17.480 --> 07:26.280] application. Prototyping is another place where I found that Lua really shines. So, sometimes you [07:26.280 --> 07:31.640] need to, you have some software that you need to build, and you only get some vague requirements [07:31.640 --> 07:40.040] communicated to you. It actually helps to have the agility of this dynamic typed garbage [07:40.040 --> 07:45.920] collected language, but still have the flexibility of calling maybe into C dependencies that you [07:45.920 --> 07:52.800] will need later on. And then just, as you go, switch out C from Lua and Lua from C. And the [07:52.800 --> 07:58.560] third thing, and really, this is, in my opinion, is where Lua shines the most is, so, plugins and [07:58.560 --> 08:06.040] extensibility. If you want to make your application extensible, your C application extensible, so, [08:06.040 --> 08:10.200] if you just do it with C, you would say, okay, you need to build a shared object using this [08:10.200 --> 08:17.440] specific API, and then we'll do a DL open. Pretty annoying. Sometimes, if you have to explain to [08:17.440 --> 08:25.280] some people what a compiler is, then it already goes beep in their head. So, Lua, you just define a [08:25.280 --> 08:33.160] simple API and makes your application almost immediately extensible so that a third party can [08:33.160 --> 08:40.320] inject their logic into your application. It means that you don't have to implement all the [08:40.320 --> 08:48.200] features that people need. They can do it for themselves very easily. So, how hard is it to do [08:48.200 --> 08:56.720] this? Well, so, a bit of a risky move to have only code on the slide, but let's do this. Imagine [08:56.720 --> 09:03.600] you have a Lua file that contains a trivial function that returns the sum of two integers, [09:03.600 --> 09:09.840] A and B. You want to call this from your C code, you initialize your Lua state, you load this [09:09.840 --> 09:17.240] file, file gets executed, well, you need this file gets put on the stack, you need to execute this [09:17.240 --> 09:26.560] through, well, a Lua call. This will register everything that is in the file into the global [09:26.560 --> 09:33.920] scope, and at this point, this add function becomes available to your Lua. You can get it, [09:33.920 --> 09:40.840] you retrieve it from the global scope, it gets put back on the stack, you push both arguments [09:40.840 --> 09:46.520] onto the stack, you do another call, this time specifying that there are two arguments, one [09:46.520 --> 09:53.240] return value, and the final argument is basically that, well, it's for error handling that's beyond [09:53.240 --> 09:59.720] the scope of this presentation. Your Lua function will be executed, and then it puts the return [09:59.720 --> 10:04.880] value onto the stack, and then using this Lua to integer call, you can retrieve it from the stack, [10:04.880 --> 10:12.520] you're back in C land, your Lua has finished running, and so eight function calls, and you [10:12.520 --> 10:21.680] unlock a whole new world of possibilities in your C application. Of course, this is, well, [10:21.680 --> 10:29.880] check your return values, that's omitted for the slide, of course, make sure that, yeah, check for [10:29.880 --> 10:41.880] errors, that's important. So the other way around, you can have a, so we just covered the calling [10:41.880 --> 10:47.600] Lua from C, another, the other option is, of course, that you call your C code from Lua, [10:47.600 --> 10:54.360] the way to do that is by creating these Lua C functions, they always have the same signature, [10:54.360 --> 11:01.720] they take single argument, this Lua context, Lua state, and they return an integer, which is the [11:01.720 --> 11:09.080] number of variables that they put on the stack as return values. Functions will always look the [11:09.080 --> 11:16.880] same, pop the arguments from the stack, do some useful work, push the results back onto, push [11:16.880 --> 11:23.240] the results back onto the stack, you create an array of this Lua registry functions where you [11:23.240 --> 11:29.000] have a name plus a pointer to the function, a sentinel value to mark the end of the array, [11:29.000 --> 11:36.440] and then you have a Lua open underscore and then the name of your, the name of your, the name of [11:36.440 --> 11:42.560] your module, which returns a new lip, so this will put your module that you just created onto the [11:42.560 --> 11:51.440] stack and return one for a single return value, and by doing this you can then load the module in [11:51.440 --> 12:00.760] your Lua code and then call into the C code without any, well, call into the C code and get the [12:00.760 --> 12:11.400] result back. Of course, having to do, well, having to build a shared object might be a bit annoying, [12:11.400 --> 12:17.640] you have to convince your, you have to convince your build system to create a shared object for [12:17.640 --> 12:23.800] you, there's no, and there's no way to share then between a C application and your Lua code, [12:23.800 --> 12:31.320] so there's a, there's a fix for that actually, you can publish internal functions in your Lua [12:31.320 --> 12:41.040] application, so functions that exist within your C application and make them available to a Lua [12:41.040 --> 12:46.800] context that is created in that application, by combining basically the previous two approaches, [12:46.800 --> 12:56.880] so same thing here, subtract function defined as a Lua C function, returns the result of A-B, [12:56.880 --> 13:05.400] you register it and then in your code you can just say, you can just push this Lua new lip, [13:05.400 --> 13:11.640] so the module that will be created, it's actually, it's actually a table with function pointers [13:11.640 --> 13:17.680] because everything is a table in Lua, and then instead of, well, instead of it being a shared [13:17.680 --> 13:22.120] object and being registered, you can just say, okay, the thing that I just put on top of the [13:22.120 --> 13:29.400] stack, make it global and have it be, and make it global under the following name, so in this case, [13:29.400 --> 13:37.480] C arithmetic, and in that case, any other Lua script that you use doesn't even have to load the [13:37.480 --> 13:41.800] module, it will automatically be loaded, it's already in the context, and so wherever you're [13:41.800 --> 13:46.760] doing this, you can just say, you can just call this C arithmetic module and then the functions [13:46.760 --> 14:01.960] that exist within there, so in short, Lua can, well, you could say Lua can help you get more done [14:01.960 --> 14:10.680] quicker, but keeping this, being a virtuous programmer in mind, I think that Lua can definitely [14:10.680 --> 14:21.480] help you embody this virtue of laziness, and so there's some time left even. I, all the code [14:21.480 --> 14:29.720] that was in the presentation, I basically have some executable examples for that open GitLab, [14:29.720 --> 14:41.000] if you want to check it out, and that's it, so thank you for your attention. If you have any [14:41.000 --> 14:45.320] questions, or you want to tell me I'm wrong, or you want to talk to me about something I'll be [14:45.320 --> 14:59.800] in the hallway after your presentation, so thank you. Thank you. We have 20 seconds, if we have [14:59.800 --> 15:16.280] one question maybe, very quick one.