diff --git a/developer-handbook.md b/developer-handbook.md index 7c142c0c..7ccdda6c 100644 --- a/developer-handbook.md +++ b/developer-handbook.md @@ -54,6 +54,72 @@ All components have a platform indicator next to them: * Pointer and reference designators should be bound to the identifier name and not the type, unless there is not identifier name. +### Write C++, Not C + +On the surface, it seems like C++ changes the way we do things from C for no +reason, but there are reasons for many of these duplications of functionality. +The C++ language designers aren't stupid, trust them or question them, but +don't ignore them. + +#### Casting + +Do not use C-style casts. C++ casts are more readable, and more explicit about +the type of cast being used. Do not use ```dynamic_cast``` in code building for the +GBA, as RTTI is disabled in GBA builds. + +#### Library Usage + +C++ libraries should generally be preferred to C libraries. C libraries are +allowed, but pay extra attention. + +This example from nostalgia::core demonstrates the type of problems that can +arise from idiomatically mixed code. + +```cpp +uint8_t *loadRom(const char *path) { + auto file = fopen(path, "r"); + if (file) { + fseek(file, 0, SEEK_END); + const auto size = ftell(file); + rewind(file); + // new can technically throw, though this project considers out-of-memory to be unrecoverable + auto buff = new uint8_t[size]; + fread(buff, size, 1, file); + fclose(file); + return buff; + } else { + return nullptr; + } +} +``` + +In practice, that particular example is not something we really care about +here, but it does demonstrate that problems can arise when mixing what might be +perceived as cool old-school C-style code with lame seemingly over-complicated +C++-style code. + +Here is another more concrete example observed in another project: +```cpp +int main() { + // using malloc does not call the constructor + std::vector *list = (std::vector*) malloc(sizeof(std::vector)); + doStuff(list); + // free does not call the destructor, which causes memory leak for array inside list + free(list); + return 0; +} +``` + +The code base where this was observed actually got away with this for the most +part, as the std::vector implementation used evidentally waited until the +internal array was needed before initializing and the memory was zeroed out +because the allocation occurred early in the program's execution. While the +std::vector implementation in queston worked with this code and the memory leak +is not noticable because the std::vector was meant to exist for the entire life +of the process, other classes likely will not get away with it due to more +substantial constructors and more frequent instatiations of the classes in +question. + ### Pointers vs References Pointers are generally preferred to references. References should be used for @@ -157,68 +223,11 @@ void studioCode() { } ``` -### Write C++, Not C +### File I/O -On the surface, it seems like C++ changes the way we do things from C for no -reason, but there are reasons for many of these duplications of functionality. -The C++ language designers aren't stupid, trust them or question them, but -don't ignore them. +All engine file I/O should go through nostalgia::core::Context, which should go +through ox::FileSystem. Similarly, all studio file I/O should go throuh +nostalgia::studio::Project, which should go through ox::FileSystem. -#### Casting - -Do not use C-style casts. C++ casts are more readable, and more explicit about -the type of cast being used. Do not use ```dynamic_cast``` in code building for the -GBA, as RTTI is disabled in GBA builds. - -#### Library Usage - -C++ libraries should generally be preferred to C libraries. C libraries are -allowed, but pay extra attention. - -This example from nostalgia::core demonstrates the type of problems that can -arise from idiomatically mixed code. - -```cpp -uint8_t *loadRom(const char *path) { - auto file = fopen(path, "r"); - if (file) { - fseek(file, 0, SEEK_END); - const auto size = ftell(file); - rewind(file); - // new can technically throw, though this project considers out-of-memory to be unrecoverable - auto buff = new uint8_t[size]; - fread(buff, size, 1, file); - fclose(file); - return buff; - } else { - return nullptr; - } -} -``` - -In practice, that particular example is not something we really care about -here, but it does demonstrate that problems can arise when mixing what might be -perceived as cool old-school C-style code with lame seemingly over-complicated -C++-style code. - -Here is another more concrete example observed in another project: -```cpp -int main() { - // using malloc does not call the constructor - std::vector *list = (std::vector*) malloc(sizeof(std::vector)); - doStuff(list); - // free does not call the destructor, which causes memory leak for array inside list - free(list); - return 0; -} -``` - -The code base where this was observed actually got away with this for the most -part, as the std::vector implementation used evidentally waited until the -internal array was needed before initializing and the memory was zeroed out -because the allocation occurred early in the program's execution. While the -std::vector implementation in queston worked with this code and the memory leak -is not noticable because the std::vector was meant to exist for the entire life -of the process, other classes likely will not get away with it due to more -substantial constructors and more frequent instatiations of the classes in -question. +ox::FileSystem abstracts away differences between conventional storage devices +and ROM.