Hello,
If you’ve been around here the last couple of months you might have heard me mention a few times that I have been working on a module loading system designed for Codea. I’ve been using it now for quite a while in it’s current state, and I feel that while it’s not yet ready for prime time, it is stable (and hopefully useful) enough to share a “pre-release” version of it. I will consider it at 1.0 when a) Codea supports optional tab execution (which is in the feature tracker), and b) when I figure out how to make it work with exported projects (currently it can only be used within the Codea app itself).
cmodule itself can be found here: https://gist.github.com/apendley/5411561
and a small test suite with basic examples of usage can be found here: https://gist.github.com/apendley/5594141
Why use cmodule? Codea’s basic module structure is great for prototypes and projects of smaller scope. However, as projects grow larger in scope and become “real” projects, it can be quite cumbersome to manage the global namespace, dependencies, as well as ensuring that your program does not fill up the iPad’s memory with code/data that is used only infrequently (e.g. game data, like levels, spritesheet metadata, etc). These problems can all be amplified as well when collaborating with others.
cmodule attempts to fully address this. With cmodule, you can load a tab (file) from any other Codea project on demand, without having to include that project as a Codea dependency (and thus, without cluttering the global namespace). By default, the source code in a module file is not loaded/executed until it is explicitly loaded with cimport/cload, so only modules that are actually used get loaded into memory (and, the garbage collector will collect them when they are no longer used). Additionally, since dependencies are explicit, and are imported locally to each module, debugging can become less of a chore: there’s only so many things a module can break, especially when taking care not to access the global environment unnecessarily from inside the module. cmodule also provides a stack trace for module compiler errors, making it much easier to track down typos or malformed code. Also, cmodule provides a way to load application data/code in an optionally sandboxed environment (using the cload function), which allows you to safely expose only the data and functions necessary for the data file to do it’s job (since, after all, the data files are Lua files).
My main motivation for cmodule is that I feel like it worth taking a stab to try and coordinate efforts for sharing code in a more standardized manner, and a module loading system can be excellent for that, if adoption becomes common (for example, it makes it much easier create shared code libraries, application/template installers, and many other things). This is my attempt at that. I fully do not expect anyone to adopt cmodule, especially in it’s early state, however I am cautiously optimistic that at least a few others will find value in both the cmodule’s methodology and the actual implementation itself. It is usually my goal when hacking in Codea to provide features that TLL will hopefully find useful enough to one day include in Codea itself (either in it’s Lua form or in a native form), thus I want to solicit feedback and get opinions on the idea and the execution itself. At the very least, I hope this can be educational/informative to others; there are a couple of neat tricks in there that are afforded by Lua’s seemingly infinite expressiveness, and you might just learn something you didn’t know from examining the code
This weekend I will move cmodule to a proper github repo (though I’ll still keep an updated Codea-packaged copy in gist at the above links) and take a stab at some proper documentation. Some of the cooler features of cmodule are not obvious, and I want to make sure to get them documented so that they may be taken advantage of.
A note about cmodule file format:
Due to the fact that Codea automatically loads and executes all tabs within a project and it’s dependency projects, module files must currently be wrapped in a long comment to prevent Codea from executing the code prematurely. Eventually Codea will support optional tab execution, and this will no longer be necessary, but for now cmodule must exist with this slightly annoying wart. As a concession, cmodule allows you to use whichever form of long comment you want, to alleviate issues with nested block comments. For example, you can use:
--[[
-- module code goes here
--]]
or:
--[=[
-- module code goes here
--[[
a nested long comment
--]]
--]=]
Essentially, you may choose to use as many = characters in your wrapper comment, and cmodule will respond accordingly.