I think C for development is presented in a much scarier light than it should be. Everywhere I go in the Playdate community, people heavily encourage others to use Lua over C because it’s “easier”. Of course there are different sorts of “easy”, and Lua is specifically easy to get started with. It is not easy to maintain a project made in Lua at all, especially when compared to C or an extension language like Zig. Here are a few cases where C is better than Lua for playdate development:
In Playdate dev, the most common case for using C instead of Lua is of course performance. Lua is an interpreted language, like Python and JavaScript, which means that code written in Lua is processed at runtime, while the game is running. This is naturally slower than compiled languages like C, where all the code is turned into a raw binary which then runs on bare metal, without needing the simulator/device to run a Lua interpreter. A neat feature of the Playdate SDK is that you can combine C with Lua by adding your C functions to the Lua environment, allowing you to write mostly in Lua while keeping the parts that require high performance in C.
Lua is also a dynamically typed language which means that variables can be set to whatever type you feel like, whereas C will throw an error if you try to set a variable to a value of a different type than it was originally. Lua functions are completely untyped, so there is no indicator for what type parameters should be or what value the function may return, unless you add comments describing all the inputs/outputs. This makes Lua a complete nightmare to debug because you can’t set proper rules for how functions and variables should be used.
Unlike other programming languages which typically have arrays, hashmaps and structures, Lua only has one data structure: the table, essentially a watered down hashmap that is also used for arrays. There is no way to set rules for which fields should be present in a given table (or what their types should be, like the rest of the language). This might be fine on a small scale but it means that there will be no errors of any sort if you make a typo when accessing or writing to a field, for example. In C you would typically use a struct for this, which requires you to define every field and its type, essentially erasing this category of bugs.
And what’s more, those table arrays start on 1 instead of 0. Most lua code and built-in functions will attempt to start with item 1 if you try to iterate over a table. Arrays starting on 1 is said to make more sense to beginners, but people arent beginners forever. If you look over any lua code you’ll find plenty of instances where accessing arrays requires adding 1 to the value used to access the field. From a programming standpoint, it simply makes sense for arrays to start on 0.
One of the biggest issues with Lua is that some of its helpful built in features, such as the ipairs()
function, can significantly impact performance, which means a lot of these features aren’t viable for projects where optimisation becomes an issue, and make Lua much less appealing as a language for me. Optimisations in Lua for the Playdate typically require sacrificing a lot of readability, and are often necessary due to the low processing power of the console:
- declaring locals early and re-declaring variables in local scope (29% performance boost)
- using a simple loop instead of ipairs (43% performance boost)
- removing functions and compressing them into other functions entirely
(86% performance boost)
Performance stats sourced from “Rules 3 -> n” Diora devlog
Optimisation in Lua typically means sacrificing readability, and ultimately undermines Lua’s main strength of being an easy language to learn and use. If a language basically requires you to use as few functions as possible because of the sheer amount of performance difference, it’s not worth using for any sort of large project (like a game). You could get away with unoptimised (and still readable) Lua code on a platform with less scarce CPU resources, like the LÖVE2D game engine, but not on the Playdate. C is the right choice for readability and performance.