blocksds / sdk

Main BlocksDS SDK repository
https://blocksds.github.io/docs/
129 stars 5 forks source link

Unifying naming conventions across libnds #169

Open asiekierka opened 1 week ago

asiekierka commented 1 week ago

Depends on https://github.com/blocksds/sdk/issues/168 - no point in starting this without first tackling that.

One of the many criticisms of libnds over the years has been the rather slapdash nature of its naming scheme. For example, functions currently may use any of the following cases:

Some functions (like soundPlayPSG or cardPolledTransfer) are prefixed with a category/namespace; others (like enableSlot1 or writePowerManagement) are not.

Structure types currently may use any of the following cases and styles:

Enum types:

Private variables and functions exported publicly but used by libnds only internally are also often not prefixed; I think they should be, either with libnds_ or __, and they should not be exposed to the end user. For example, something like int bgInit_call(int layer, BgType type, BgSize size, int mapBase, int tileBase); should be defined inside the bgInit function, so that an user cannot rely on this symbol accidentally in their production code.

The correct naming scheme should be decided and documented as part of the code style, with all functions, types and variables adjusted to match.

Naturally, of course, renaming everything will break the world. Is there something we can do about this? For a previous transition, libnds provided a registers_alt.h file, with legacy register names (slightly different, most notably - not prefixed with REG_).

There is currently a large open source project undergoing a mass rename/refactor - SDL 3. They solved this by:

I believe the best options here for our uses are 1 and 3; option 1 can be realized by creating an nds/oldnames.h file that's only included, for example, for values of BLOCKSDS_STRICT < 20000 (see https://github.com/blocksds/sdk/issues/167 ), and option 3 can probably be generated from such a file.

Note that most other libraries are ineligible - dswifi is maintenance-only, maxmod is already fairly well prefixed, and many other libraries are provided by third parties - they could follow the same roadmap, but we obviously can't force them to.

profi200 commented 1 week ago

I feel like i have to explain the reasons why i named my code the way it is.

Code style is always a matter of preference you will probably get as many opinions as there are devs.

asiekierka commented 1 week ago

Code style is a matter of preference, and I'm not criticizing any particular naming convention here; the goal is to get away from a situation where we have eight naming conventions for structure types, and unify them for the present and future.

(Besides, it should have been my responsibility as the committer in such a situation to unify code styles, not yours.)

AntonioND commented 1 week ago

Private variables and functions exported publicly but used by libnds only internally are also often not prefixed; I think they should be, either with libnds_ or __, and they should not be exposed to the end user. For example, something like int bgInit_call(int layer, BgType type, BgSize size, int mapBase, int tileBase); should be defined inside the bgInit function, so that an user cannot rely on this symbol accidentally in their production code.

https://en.cppreference.com/w/c/keyword

Also, each name that begins with a double underscore _ or an underscore followed by an uppercase letter is reserved

libnds_*** is fine, but __*** is reserved.

Regarding situations like bgInit_call we don't need to use things like functions inside functions, we can just mark everything non-public as static, including private variables.

asiekierka commented 1 week ago

we don't need to use things like functions inside functions, we can just mark everything non-public as static, including private variables.

The idea is that an user should never call bgInit_call (libnds_bgInit_call) directly. By putting the definition inside the function body, it never escapes that block - this means we can define such functions in f.e. static inline functions without making them part of the public API.

AntonioND commented 1 week ago

Yes, but I mean that instead of using C extensions we can just have the functions as regular non-nested functions and mark them as static. I think this helps with clarity because most people won't expect nested functions to be there.

In any case, this is a minor thing, I agree with the rest.

asiekierka commented 1 week ago

https://github.com/blocksds/libnds/pull/106#discussion_r1645153298

Moving away from card/cart to slot1/slot2 should also be discussed as part of this.

asiekierka commented 1 week ago

Yes, but I mean that instead of using C extensions we can just have the functions as regular non-nested functions and mark them as static. I think this helps with clarity because most people won't expect nested functions to be there.

No, that's incorrect. Let me explain based on background.h:

int bgInit_call(int layer, BgType type, BgSize size, int mapBase, int tileBase);

static inline int bgInit(int layer, BgType type, BgSize size, int mapBase, int tileBase)
{
    return bgInit_call(layer, type, size, mapBase, tileBase);
}
// the `bgInit_call` definition still pollutes the user's namespace

versus

static inline int bgInit(int layer, BgType type, BgSize size, int mapBase, int tileBase)
{
    int bgInit_call(int layer, BgType type, BgSize size, int mapBase, int tileBase);
    return bgInit_call(layer, type, size, mapBase, tileBase);
}
// no pollution

You can't use static here, as bgInit_call (or, as it would be renamed to, libnds_bgInit_call) is an external symbol. It's defined in libnds9.a.

AntonioND commented 1 week ago

Ah, okay, I see what you mean. But, to be fair, in that case we should just move the wrapper function to the .c file instead of the .h file, and let the compiler optimize things.

We did something similar in https://github.com/blocksds/libnds/commit/24565646727c3ed05cf6b7897b5524d20279d469 when it become a problem to have the implementation of a function in a header.

asiekierka commented 1 week ago

Ah, okay, I see what you mean. But, to be fair, in that case we should just move the wrapper function to the .c file instead of the .h file, and let the compiler optimize things.

I'm not so sure about that. Remember the compiler won't optimize function calls across translation units unless we get LTO working.