[00:00.000 --> 00:11.640] Welcome. I am Bess Vandenberg. I have been working on a language called C2 for about [00:11.640 --> 00:20.720] 11 years now. I did two talks in FOSDEM in 2013 and 2015, I think. So this is the third [00:20.720 --> 00:29.800] one about the compiler, so it's slightly different. So the presentation roughly has three parts. [00:29.800 --> 00:32.840] First the language introduction, because you can't talk about a compiler without knowing [00:32.840 --> 00:40.440] the language. Then the evolution of the C2 compiler, which is called C2C, because CC [00:40.440 --> 00:48.760] was already taken, of course. And then the next steps, so three parts. The first part, [00:48.760 --> 00:58.320] the language. There's a lot of info here. My reason for starting C2 was I'm an embedded [00:59.040 --> 01:03.520] developer, so I work a lot with low level systems kernels and that sort of thing. And [01:03.520 --> 01:08.920] everyone was getting new programming languages except embedded programmers. So we are still [01:08.920 --> 01:19.800] writing kernels in C and no other programming language are really making it in that race. [01:19.800 --> 01:25.360] So I thought, well, we should be able to do something about that. So I love C, so let's [01:25.400 --> 01:31.360] try to keep the good parts and remove the parts that have become somewhat older with [01:31.360 --> 01:38.160] time, since C is, of course, 50 years old. So what I did was I looked at the anti-patterns [01:38.160 --> 01:47.240] in C. For example, the types you define like Uint, 32T, and lots of macros, lots of plumbing [01:47.240 --> 01:53.880] you have to do that everyone does in every project, like the size of an array macro. [01:53.880 --> 02:00.080] And that's tried to get those out. Also, the header files had to go, because header files [02:00.080 --> 02:05.480] you had to type, yeah, your definitions twice and it's a hassle with a lot of stuff, a lot [02:05.480 --> 02:13.080] of tooling. Macros as well. So the macros also went out. And the goal was to get better [02:13.080 --> 02:19.440] development speed. So execution speed in C is not a problem, of course, but yeah, development [02:19.440 --> 02:29.560] speed is. Then the speed of execution can be better than C. That's because full program [02:29.560 --> 02:36.880] optimization is easy in C2 and it's quite hard in C in a realistic program. So you can [02:36.880 --> 02:45.080] get better execution speed that way. It also has a built-in build system. So the scope [02:45.080 --> 02:50.520] of the C2 compiler is different than a C compiler. The C compiler, you feed it a single [02:50.520 --> 02:55.080] C file, it produces an O file, and then you do that a lot of times and the linker just [02:55.080 --> 03:03.080] collects everything and turns it into an executable. In C2, you run the C2 compiler, it takes a [03:03.080 --> 03:12.080] lot of source files and produces the binary. So it does use the linker, but the translation [03:12.080 --> 03:18.760] unit is the whole program. So it can do a lot of diagnostics that the C compiler can [03:18.760 --> 03:25.080] do. Like this field in this truck is never written in the whole program. So in C, that's [03:25.080 --> 03:32.960] not possible unless it's in the static part, in the C file for example. And I tried to [03:32.960 --> 03:42.120] get better tooling, like jump to definitions that are reliable and fast, analyzers that [03:42.120 --> 03:51.920] are often hindered in C by the macro use, and so on. What I'm not trying to do is make [03:51.920 --> 03:58.800] a completely new language, like Rust or Go, because it should be recognizable by C and [03:58.800 --> 04:03.920] because I like the things in C, the abstraction layer is just to do it yourself, and it fits [04:03.920 --> 04:10.680] the hardware we have now, so that's okay. And I also don't want to add higher level [04:10.680 --> 04:17.120] features like garbage collection or runtime, because it's not the domain I'm trying to [04:17.120 --> 04:28.200] use it for. So let's see an example. How many people ever looked at a piece of C2 code already? [04:28.600 --> 04:45.280] Probably a few. Well, every file... The dog did. Every file starts with a module definition [04:45.280 --> 04:50.520] where you define every file as part of a module, and a module is just a piece of code. Different [04:50.520 --> 04:55.920] files can belong to the same module. Then you get a bunch of definitions like a type [04:56.000 --> 05:02.640] and two functions. The order here doesn't matter. The ordering is for a compiler, not [05:02.640 --> 05:08.840] for humans. There are no forward declarations. In 50 years ago, when the compiler had memory [05:08.840 --> 05:14.080] problems, it was an issue. So the user, the programmer had to structure the program, so [05:14.080 --> 05:20.520] I first do the forward declaration, and then like this part, the element points to an element [05:20.520 --> 05:24.200] again in C. That's not possible. You have to do forward declaration of the struct, and [05:24.200 --> 05:30.200] then the definition, that's a computer problem, and it should be able to do that. [05:32.200 --> 05:38.000] A second thing you'll notice here is the public keyword. Types and functions can be public [05:38.000 --> 05:49.000] or not. Public means it can be called by other modules. Another one is this one. This is called [05:49.000 --> 05:53.760] a struct function. So we have a struct, and we can just add these functions to it, and you [05:53.800 --> 06:00.800] can, in the next slide, also, you can do element dot in it. You can add them arbitrarily. Not [06:00.800 --> 06:09.300] just in C++, but you have to add it in the class definition. Another change from C was [06:09.300 --> 06:14.600] the dot here. These are pointers. In C, you have to use the arrow, and a dot for the full [06:14.600 --> 06:21.600] body. In C2, we make no difference. It's all a dot, because it's better readable. [06:24.120 --> 06:29.080] Okay, so how do we use this part? This is just an example, of course. It would roughly [06:29.080 --> 06:36.080] look like this. So you import the list, the linked list module, use the element, and then [06:36.600 --> 06:42.800] do something with it. The thing to note here is that the import has no file name. So in [06:42.800 --> 06:48.160] C, you do includes, and includes has a file name. It has a path or a sub-directory. That's [06:48.200 --> 06:54.560] all very unhandy when you try to reuse stuff, and it's in the utils library directory, and [06:54.560 --> 06:59.280] in another project, in the lib directory, you have to change the header files and includes. [06:59.280 --> 07:04.200] That's not the case here. You can just put the files somewhere on your file system in [07:04.200 --> 07:11.200] your project, and I'll show that later, and in your recipe file, and then it will work. [07:12.280 --> 07:18.040] But otherwise, if you look at the body function body, it's pretty similar to C. So the [07:18.080 --> 07:23.240] plumbing, like the rest of it, looks different, but if you have a large function with four [07:23.240 --> 07:26.240] loops, it's just the same. It looks really the same. [07:30.840 --> 07:35.160] So because the scope of the C2 compiler is the whole program, you have to tell it what [07:35.160 --> 07:41.240] to do. So you just run C2C, and you can give it arguments, but you don't have to. It will [07:41.240 --> 07:47.760] look up the recipe file, and then do whatever you want. So you can turn it into an extra [07:47.800 --> 07:53.880] executable or a library. These are the files, so it will not dynamically look for files [07:53.880 --> 08:00.560] with some name. It will also not use directory structures as the module name or something, [08:00.560 --> 08:07.560] like some languages do, but it will do this. And also, this is the configuration part. [08:10.680 --> 08:17.200] There are only a few options. In CUF, I have given actually presentations about the warning [08:17.240 --> 08:22.240] flags in C. In C2, the only warnings you have is unused. The rest is just an error. [08:26.640 --> 08:32.240] So unused can be, of course, if you are refactoring, it can be annoying. You can temporarily [08:32.240 --> 08:38.240] silence them, but other stuff you can't ignore. You have to fix it. [08:38.560 --> 08:45.560] So, what other features does the language have? Modules, imports, with the recipe file. We [08:47.680 --> 08:53.200] have a lot of stuff like elements of, which is the built-in function, like size of, but [08:53.200 --> 08:58.800] then for array sizes. We have enum min, enum max, which is the first and the last element [08:58.800 --> 09:04.920] or the highest element in an enum, offset of to container, which are usually macros in [09:05.040 --> 09:12.040] C, but they are part of the language here. Also, the base types are all in there. We have [09:13.120 --> 09:19.640] opaque data types, which are types in C that you only use by pointer. So, like you have [09:19.640 --> 09:25.040] some component and you call a create function, you get a handle back, but you cannot, you [09:25.040 --> 09:29.840] can only use the handle by pointer. You cannot actually look into it, and that's opaque data [09:29.840 --> 09:36.840] types. That's made explicit here. Another thing you can do, because we have full program [09:38.360 --> 09:45.120] scope, is global incremental arrays, which are just array, global arrays, but you can [09:45.120 --> 09:50.240] define them in different files and you can have them behind the configuration sort of [09:50.240 --> 09:55.240] if-devs. So, if you have this feature, these elements are added to the array and otherwise [09:55.360 --> 10:00.120] they don't. But in the end, the compiler will put them all together and turn it into a single [10:00.120 --> 10:07.120] array. Another feature I've never seen in other languages is the build file. It's also [10:10.080 --> 10:17.080] another file, which is optional. The recipe and the code is made by the developer, but [10:17.240 --> 10:22.280] the other users of a program can be, for example, open embedded or Yocto systems, where you [10:22.320 --> 10:28.820] have to tell it how to build where the directories are, and that is specified in a build file. [10:28.820 --> 10:35.820] So, that's not created by the developer, but by the users or the package managers or those [10:36.040 --> 10:42.040] people. Another feature, which I haven't seen in other languages or compilers is plugins. [10:42.040 --> 10:48.000] So, the C2 compiler has a plugin system. You can write plugins for it to walk the ASD, [10:48.000 --> 10:54.440] do stuff with it, either before parsing the other stuff or after. I'll come back to that [10:54.440 --> 11:01.440] later. Let me check the time. Current state. We have 900 unit tests. It does run, so it's [11:05.760 --> 11:12.760] quite okay. It gives quite nice diagnostics. Weird cases are all covered. Doesn't mean [11:13.760 --> 11:20.760] there aren't more. There probably are a lot. Lipsy support, pthread support. I once supported [11:21.560 --> 11:28.560] the Vulkan library, the Graphics library to C2 that worked, well, written web server, [11:28.560 --> 11:33.280] web socket server event framework. There are plugins for VIM or Neo VIM to jump to definitions [11:33.280 --> 11:40.280] that are really fast and correct. We can generate dependency matrixes of the whole code to some [11:42.760 --> 11:49.760] format, also through plugins. This part, the embedded user is still in progress, so that's [11:50.160 --> 11:56.120] the bare metal case. You need linker scripts for that. Inline assembly is supported already, [11:56.120 --> 12:02.800] but you need more for that. You also need the bare assembly. And it's been used in some [12:02.800 --> 12:09.800] production code, web server client and customer service for customers I work for. I advise [12:09.880 --> 12:16.880] them to use C2. Okay. So the second part is about the evolution of the compiler itself. [12:22.440 --> 12:27.160] Started in 2012. Well, you started by Zonjak because you're doing something with parsers. [12:27.160 --> 12:33.280] I quickly found out that they're not really usable in real projects, really hard to use. [12:33.280 --> 12:40.280] So I started with a patch on Clang, 3.2 in 2013, when Clang was a bit more slimmer, to [12:43.800 --> 12:50.800] parse C2. After that, I created an own C++ code base using many components from Clang. [12:52.080 --> 12:59.080] The patched preprocessor, tokenizer, also the diagnostics engine and generic LLVM components. [12:59.880 --> 13:04.880] That went on for quite a long time. It went well. Always rebasing on the latest LLVM, [13:04.880 --> 13:10.880] like 3, 4, 5, 6, 7, 8. We're now at 11, I think, or 12. Well, the latest rebase. [13:10.880 --> 13:17.880] Added to own custom unit test framework. And last year, the plugins, which is quite nice [13:20.040 --> 13:27.040] because like for the, so I have another slide for that. So that's this one. Yeah, this one. [13:28.040 --> 13:35.040] So some, the C2 compiler shouldn't depend on a VIM plugin, of course, but there's some [13:35.560 --> 13:40.520] sort of dependency on it. So we put that in it. You can create a plugin that generates [13:40.520 --> 13:45.920] walks, the AST, gets information out, puts it in some binary file, and the plugin can [13:45.920 --> 13:51.720] look at the binary file. So that works really well. And there's also another fun stuff to [13:51.720 --> 13:57.200] do, like shell commands to symbol. So you can, in a YAML config file, you can pass to [13:57.200 --> 14:03.040] these plugins. You can specify, I want to run this command, like git version or ls, [14:03.040 --> 14:08.040] and then put it in this C symbol. So you get it in C, you can just use the symbol name [14:08.040 --> 14:15.040] in your scope. And yeah, you get the information. So that's quite nice. Git version works the [14:15.840 --> 14:20.800] same way, but it's just specialized for this. Also load file. So you can, you have a load [14:20.800 --> 14:25.320] file plugin. So you specify, I want to load this file, and this is the symbol name. And [14:25.320 --> 14:28.880] the symbol name is just straight with the data field and the length field. So you can [14:28.880 --> 14:35.380] just access the content. So you don't need to have macros or scripts that convert stuff [14:35.380 --> 14:42.140] to header files and import those. Other IDs are to code obfuscation stuff and additional [14:42.140 --> 14:48.640] checks you can implement in companies, like every name should be 13 bytes long, whatever [14:48.760 --> 14:55.760] you want. So continuing on the list. Last year I started on rewriting the C2 compiler in C2, [15:03.600 --> 15:09.200] because that's the domain it's also meant for. So it was a sort of graduation project. [15:09.200 --> 15:14.760] See if it's valid. It was also the biggest project. It's now, I think, 15,000 lines of [15:14.800 --> 15:21.800] code or something. So to do that, you need to bootstrap it. So that was done this year. [15:23.200 --> 15:30.200] So we now have a bootstrap way to, yeah, to start with a normal C compiler and bootstrap [15:30.200 --> 15:37.200] that into a C2 compiler. That's shown in this image. So it's quite a hassle sometimes. [15:37.640 --> 15:44.640] So we start with the C++ sources for C2C, compile those with Clang++. We get a C2 compiler. [15:48.280 --> 15:53.800] Then we take the C2 sources, the native version, the C2 version, compile that with this compiler, [15:53.800 --> 16:00.720] get a C file we can generate C, if you want. Compile that with Clang and then do that again [16:00.720 --> 16:06.200] to the bootstrap because we want to use this final compiler to do another step. So then [16:06.200 --> 16:13.200] we get a C2 compiler that's the final one. And the bootstrap actually starts here. So [16:15.280 --> 16:22.280] we save this file. That's easy. It's quite a big file, but Clang can handle it. And the [16:23.240 --> 16:30.240] bootstrap is just the last part. So, well, I had first ideas to use binaries, but if [16:30.240 --> 16:37.240] you lose the one binary you have, then you cannot compile again. That's not so handy. [16:42.400 --> 16:47.480] I think the project was a success with the graduation. I found quite a lot of bugs in [16:47.480 --> 16:54.480] the old C++ version of the compiler, but it's quite nice. I was afraid that C or C2 like [16:55.480 --> 17:01.480] languages might be too low level because Clang is, of course, written in C++, but in a compiler [17:02.400 --> 17:09.400] you can use memory pools and quite a lot for the AST, and that's also faster. So memory [17:09.960 --> 17:16.960] management is not really an issue here. It now parses roughly four million lines a second. [17:17.360 --> 17:23.920] And analysis is also quite fast. That's because we do the whole program at once. So when you [17:23.920 --> 17:28.920] do a C program, your make files kicks in. It takes the first while, puts it in GCC, [17:28.920 --> 17:34.120] get an O file, and does some parallelism with multi-course. But it does code generation [17:34.120 --> 17:41.120] as well here, and then the second one and the third. So if your file number 100 has [17:41.600 --> 17:47.520] an error, you only get an error after 99 files have been compiled. And in C2 you parse all [17:47.520 --> 17:54.520] the files, check all the files, so it's really fast. It takes milliseconds. So I can announce [17:58.720 --> 18:04.480] now the public repository. I open sourced it yesterday. Had to add some legal headers [18:04.480 --> 18:11.480] and stuff, of course. I get some open source license in there. So it's now on GitHub. You [18:11.480 --> 18:17.440] can download it and try it. It's not as functional as the C++ version, so that's still the main. [18:18.120 --> 18:25.120] So the next step will be to convert all the unit tests to the new, actually the compiler [18:25.840 --> 18:32.160] to fit all the unit tests we have. Sometimes the diagnostics differ a bit, so I have to [18:32.160 --> 18:39.160] change the unit test. Also, when I implemented the C2 compiler in C2, I had to run, I had [18:40.160 --> 18:47.160] to use a lot of vectors as data types for lists of stuff, and you have to retype them [18:47.520 --> 18:53.880] every time you see. So I started playing around with templates. The start is now in there, [18:53.880 --> 18:59.200] but it needs to be expanded because it's quite nice to have some form of templates. I'm trying [18:59.200 --> 19:06.200] to stay far away from the C++ hell, of course, but at least something. The recipe file format [19:07.080 --> 19:10.800] will be changed to YAML because the build file is also in YAML and all the other files [19:10.800 --> 19:17.800] also, so that's more consistent. Then currently there are three backends, so the code gets [19:18.440 --> 19:23.520] converted through the backend to something else. One is the C backend, which is quite [19:23.520 --> 19:30.520] easy, and then we also generate make files, and it just runs it and gets a binary. Another [19:30.920 --> 19:37.560] backend is QBE, which was presented here last year. It's a small backend that has no optimization, [19:37.560 --> 19:43.320] but it works, and it's quite easy to use. Then there's also beginning of the LLVM backend, [19:43.320 --> 19:48.920] which is quite hard because LLVM is like a client, it's a huge dragon, it's millions [19:48.920 --> 19:55.920] lines of code. That's more work, so this is the step up to LLVM. Last is the embedded [19:56.920 --> 20:03.920] words used, so it's using linker scripts and allowing bare metal. That would be nice. [20:10.560 --> 20:17.060] So that's the presentation. I tried to keep it quite short and not focus only on the language [20:17.060 --> 20:24.060] itself, so there's room for questions. If there are any. [20:25.920 --> 20:32.920] So how do you interact with C code in particular with C headers? [20:37.280 --> 20:42.720] From a C2 project, you can generate C headers for your C2 library, a library that's written [20:42.720 --> 20:43.720] in C2. [20:43.720 --> 20:46.800] So I meant if you want to use a library written in C. [20:46.800 --> 20:51.560] Yes, so that's one way. The other way is if you have a C library like the Vulkan library, [20:51.560 --> 20:58.560] you have to create a sort of C, C2 interface file, so it's like a header file in C. It's [20:58.560 --> 21:05.760] quite straightforward, but it's manual work. There's no way to automate that currently. [21:05.760 --> 21:10.800] But the rest is the ABI is the same for the libc. You just have to define like printf, [21:10.800 --> 21:14.560] this is the function. [21:14.560 --> 21:19.560] So the question was how do you interact between C and C2? [21:20.560 --> 21:27.560] So you said that with your C2 compiler, the whole program will be compiled in one step. [21:27.560 --> 21:32.560] Do you have provisions for building shared libraries or other things that cannot be compiled [21:32.560 --> 21:37.560] into one step? What if the program is so large that we cannot compile and link it in one step? [21:37.560 --> 21:43.560] This is the case with many C++ projects if you do not have enough memory. [21:43.560 --> 21:50.560] If you take a really large program, it will probably take a tenth of the size of your browser. [21:50.560 --> 21:56.560] Loading a standard web page takes so many megabytes. Like a huge program like the Linux kernel, [21:56.560 --> 21:59.560] it fits in a few megabytes ASD in C2. [21:59.560 --> 22:04.560] That is true, but I'm working with a lot of software packages I'm doing packaging. [22:04.560 --> 22:09.560] And these days it's very frequent that some C++ software no longer compiles in 32 bits [22:09.560 --> 22:13.560] because the Clang process exceeds the 40-bit virtual average base. [22:13.560 --> 22:18.560] And that is because even if the ASD is just a couple megabytes, the internal data structures [22:18.560 --> 22:25.560] to represent all the things the optimizer is looking for are a hundred-fold of the size, a thousand-fold maybe. [22:25.560 --> 22:31.560] So that's an interesting question maybe for the future when C2 programs grow very big. [22:32.560 --> 22:39.560] Yeah, I looked at that. When I was working on the Linux kernel, [22:39.560 --> 22:44.560] I created a program to see how many lines of code the compiler actually had to parse, [22:44.560 --> 22:52.560] like a thousand files of C and how lots of files get included many times recursively also again. [22:52.560 --> 22:55.560] So the factor was roughly a factor of a hundred. [22:55.560 --> 23:01.560] So every thousand lines of code you create the compiler to parse like a hundred thousand lines [23:01.560 --> 23:04.560] and also analyze and stuff to stuff with it. [23:10.560 --> 23:15.560] But I think the biggest part will be probably the representation in LLVM [23:15.560 --> 23:21.560] and we can do that step by step because the modules are directed as cyclic graph. [23:21.560 --> 23:26.560] So they have a structure, one at the bottom and one at the top. [23:26.560 --> 23:28.560] So we can do them one by one. [23:37.560 --> 23:42.560] In the first slide you've shown that you can define methods and structures. [23:42.560 --> 23:46.560] So the question is do you have some kind of name mangling? [23:46.560 --> 23:55.560] Yes, you need to do some mangling but let's see here. It's really simple. [23:55.560 --> 24:01.560] In effect what we do we take the linked list, put the underscore at this one [24:01.560 --> 24:05.560] and this one is turned into an underscore so that's it. [24:09.560 --> 24:12.560] No, because it needs to be recognizable. [24:13.560 --> 24:18.560] So it's a really simple forward scheme. You can go both two ways, it's really easy. [24:22.560 --> 24:26.560] No, we start with the name of the module. [24:27.560 --> 24:31.560] So it's linked list underscore element underscore init. [24:31.560 --> 24:35.560] So how do you handle the case where you're linking with a C library [24:35.560 --> 24:38.560] that has that name which is a value? It's simple. [24:40.560 --> 24:43.560] Well, that gives you an error. [24:45.560 --> 24:49.560] It's like if you define a function printf in your C program you get an error. [24:56.560 --> 24:58.560] Yeah, so you get an error. [24:58.560 --> 25:02.560] In C you have a single namespace so this is a two-dimensional namespace [25:02.560 --> 25:07.560] so it's a linked list, a module name and that already solves so many problems [25:07.560 --> 25:10.560] that your namespace will be much cleaner. [25:10.560 --> 25:15.560] So he says that the symbols started with double underscore and underscore [25:15.560 --> 25:19.560] but the uppercase are on the implementation domain. [25:19.560 --> 25:25.560] So if you prepanded double underscore to all the symbols then you would know that you would never... [25:25.560 --> 25:29.560] Okay, I didn't know that so... Okay, that's easy to fix then. [25:29.560 --> 25:31.560] So double underscore and then capital. [25:31.560 --> 25:36.560] You could also use a scheme like the go-to channel and put a symbol into the linked symbols [25:36.560 --> 25:40.560] which cannot be used in C like you can put a bot in the symbol. [25:40.560 --> 25:43.560] For example, you could name the symbol element bot in it. [25:43.560 --> 25:45.560] I would never come out of anything. [25:45.560 --> 25:47.560] It's a smiley face. [25:47.560 --> 25:51.560] If you compile a NIC at the same time, can you actually parallelize the process? [25:51.560 --> 25:54.560] Like if you have like a one million files and you have eight cores [25:54.560 --> 25:57.560] do you use only one core to compile everything? [25:57.560 --> 26:01.560] No, we use many threads so we parse everything at once. [26:01.560 --> 26:04.560] We analyze it single thread because we don't do the locking and... [26:05.560 --> 26:07.560] Yes? [26:07.560 --> 26:09.560] So the modules we have an import like here. [26:09.560 --> 26:13.560] So this module depends on this module so we can build a graph. [26:13.560 --> 26:16.560] We sort all the modules and analyze the bottom up. [26:16.560 --> 26:23.560] And we also generate code that way but the generation of the code and the optimization is 90 something percent of the work. [26:23.560 --> 26:25.560] So that's done in threads. [26:25.560 --> 26:29.560] The other part is just milliseconds really. [26:29.560 --> 26:32.560] So in the thread when the symbol is not resolved because it's another module [26:32.560 --> 26:37.560] you just put some temporary hook that whenever it's resolved by the other thread then you update the symbol. [26:37.560 --> 26:41.560] No, the analysis is done over the whole program first. [26:41.560 --> 26:42.560] Bottom up. [26:42.560 --> 26:44.560] So everything is resolved. [26:44.560 --> 26:47.560] So the generation of codes just... [26:47.560 --> 26:49.560] it doesn't change the AST. [26:52.560 --> 26:53.560] Yes? [26:53.560 --> 26:56.560] So you were mentioning generics templates. [26:59.560 --> 27:04.560] Do you already have plans on how to handle separate compilations for that? [27:04.560 --> 27:06.560] Well we don't have to. [27:06.560 --> 27:11.560] I mean in C++ every time you use a vector in FAC file it has to generate the whole code for the vector [27:11.560 --> 27:17.560] and then in the end you have like 600 implementation and the linker has to remove them. [27:17.560 --> 27:19.560] That's why C++ is so slow. [27:19.560 --> 27:21.560] So here you don't have to do that. [27:21.560 --> 27:26.560] You have one implementation per instance of per use. [27:26.560 --> 27:28.560] If you have... [27:28.560 --> 27:33.560] So you have your say standard library module that defines the vector of t [27:33.560 --> 27:39.560] then you have two modules that both use vector of t that are compiled separately for some reason. [27:39.560 --> 27:41.560] Oh, no, you can... [27:41.560 --> 27:42.560] But they're not. [27:42.560 --> 27:44.560] They're never, yeah. [27:44.560 --> 27:47.560] It's quite easy, yeah. [27:47.560 --> 27:52.560] Can you reimplement the Linux kernel in C to C without macros? [27:52.560 --> 27:57.560] I wouldn't want to because Linux kernel is not a really good example. [27:57.560 --> 28:00.560] It's one of the worst pieces of open source there is. [28:00.560 --> 28:03.560] If you try to map to dependencies you get a fully connected graph. [28:03.560 --> 28:05.560] Everything depends on everything. [28:05.560 --> 28:07.560] It's horrible, no? [28:07.560 --> 28:08.560] Yeah. [28:08.560 --> 28:09.560] Yes? [28:09.560 --> 28:11.560] Do you have a C to C? [28:11.560 --> 28:13.560] You also have a C++ version. [28:13.560 --> 28:14.560] Yes? [28:15.560 --> 28:20.560] The C to version is much smaller. [28:20.560 --> 28:22.560] But there are also... [28:22.560 --> 28:26.560] Because some clang components we use are quite heavy. [28:26.560 --> 28:28.560] So it will require a lot of code. [28:28.560 --> 28:32.560] And clang is, of course, the components we use can do more than what we need. [28:32.560 --> 28:35.560] So they're a bit fat. [28:35.560 --> 28:39.560] But otherwise, yeah, the C to code is quite slim. [28:39.560 --> 28:42.560] That's also what we do with the name stuff. [28:42.560 --> 28:45.560] Here, like list, it doesn't need any prefix. [28:45.560 --> 28:50.560] In C, if you would use C, you would probably call it linked list underscore init. [28:50.560 --> 28:53.560] So you would have to type that all here. [28:53.560 --> 28:56.560] And then pass the list as an argument. [28:56.560 --> 29:00.560] Like if you have some component in C that's called foo. [29:00.560 --> 29:03.560] You already see foo underscore this, foo underscore that. [29:03.560 --> 29:08.560] And all that stuff is just reduced to a single name at the top and that's it. [29:08.560 --> 29:12.560] So your code gets a lot smaller in column size. [29:15.560 --> 29:17.560] Time's up. I see. [29:17.560 --> 29:19.560] Alright, thank you, Bas.