-
Notifications
You must be signed in to change notification settings - Fork 3.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tidying up the Library coding styles #1028
Comments
gpio.c exemplifies one other issue (eg: serout() function) - the code for checking/reading from Lua state is mixed with the execution logic. I.e. 80% of all lines deal with getting input arguments, 20% is doing the actual work. That may be a matter of taste or necessity (a smaller footprint?) is there any 'official' guidance? (ie: why is better to have
the issue is not only about readability, functions that declare their input arguments and return values are easier to test (and the code for reading/checking values could be extracted into a macro and reused by many modules - which would be actually saving space) |
I agree that it is well worth while enforcing a clear split by doing all of the API argument validation first, the execute the functional bit. There is the issue of calling overhead both in terms of extra generated lx106 code and execution time to handle the procedural call overheads, but these can effectively removed by declaring the execution function first with an |
Terry, I agree with you but is it worth keeping this issue open? When would be a good time to close it? Clearly we don't want to keep it around until all loose coding issues in all modules are fixed? I suggest we close this and keep an eye on the issue with every PR that contains material changes. |
Bump. Don't wanna close your issues but I still think it should be closed. |
I think the best case is to use linter like cpplint, this is good enough to get readable code (consistent tab/space struct, maximum line width and more). Also configuration for e.g. Eclipse Code Formatter will be good point. Anyway I prefer automated tools more than "guidelines". |
Yuri, that's a valid input - for #1168. Look at Terry's initial example here. That's not something a linter could "fix". |
While eslint doesn't lint C/C++ code it is an example of a linter which will fix and/or identify exactly the issue. mentioned in JavaScript. Assuming I understand your inference correctly. |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
Nah, this is still very much the case. I am going through the modules ATM as part of the Lua51 + Lua53 integration and keep coming across this crap. It just adds noise to the modules that we don't need. For example every module which returns a UData resource like a socket registers a registry entry, say luaL_argcheck(L, ud, 1, "TLS socket expected");
if(ud==NULL){
NODE_DBG("userdata is nil.\n");
return 0;
} This is all totally redundant noise -- doubly redundant in this case -- and should be stripped out. Likewise in the case of const char *method = luaL_checklstring( L, 2, &sl );
if (method == NULL)
return luaL_error( L, "wrong arg type" );
|
What @nwf or I will do is a debris sweep to remove this crap. |
Reserving luaXXX names for the Lua runtimeA bunch of modules (
The wifi modules also use |
A few other peeves of mine:
luaL_unref(L, LUA_REGISTRYINDEX, ud->client.cb_connect_ref);
ud->client.cb_connect_ref = LUA_NOREF;
luaL_argcheck(L, lua_isfunction(L, N), N, "not a function");
lua_pushvalue(L, N);
luaL_unref(L, LUA_REGISTRYINDEX, func_ref);
func_ref = luaL_ref(L, LUA_REGISTRYINDEX);
|
More thoughts on what makes me uneasy about these: any form of denormalisation (storing stuff twice) makes me uneasy. You have to add extra code to the extra store and GC, plus code to handle exception cases when the two aren't the same. Why add all of this complexity? It's not the Lua way. So why so we need to do this. OS CBs typically require a context to do their job. The standard model is to pass the &UD as this context, but if they need to clean up the registry then they need to know the parent registry slot that holds the UD. So why not just use the registry index, the slot number as the context? This makes the CB code a lot simpler. |
Another on on my TODO list is to make is that various lib_init entries for modules create one or more metatable references such as |
@TerryE: whether we use the userdata pointer or a registry index as the callback parameter stored in the platform C layer doesn't matter. The ref in the registry needs to exist to keep either of those things meaningful; whether or not that ref is stored as a self-ref in the userdata structure is semantically immaterial. Syntactically, using the userdata pointer itself as the callback parameter means that some platform callbacks can avoid going to Lua to manipulate state (e.g., the The "problem", at its core, and the reason that the Lua libraries don't make self-refs like we do, is that in a Lua program without registry-like shenanigans going on,
would create an object, update some properties of it, and then immediately drop the reference on the floor and let the object be GC'd. Now, maybe in Lua one would have The appropriate point of comparison would not be the Lua standard libraries, but rather other embeddings of Lua into larger systems with persistent state. Maybe some game engine such as Love. But I'd be willing to wager $1 that they either manage objects' lifecycles outside the Lua GC or create self-refs for precisely this reason. |
Obviously I wasn't awake when I wrote that. The correct thing to do is
|
Very few of our calls can set more that one CB depending on parameters and if we only have two options then surely the simplest way to code this is: int optn = luaL_checkoption(L, 1, NULL, name);
luaL_reref(L, 2, optn == 0 ? &ud->cb0_ref : &ud->cb1_ref); |
@nwf, I agree that the architectural difference is that we have SDK-triggered CBs. In general my view is that we should only denormalise when there is a compelling reason to do so, for example there is a material performance benefit or we need to denormalise because this is the only way to access the parameter on some code paths. The downside of denormalising is that we need extra code to handle set-up, clean-up and we also need to maintain transactional integrity on update. The issue of potential loss of integrity between the two copies means that the two approaches are not semantically the same on some on error paths. We avoid this risk / code complexity if we don't denormalise. PS Edit: My comment below gives the compelling reason in this case. I am therefore striking out this example.
PS. This version also uses the |
Another point:
|
Holding on to an I'll see what it does to |
What we are really saying is that the state will always be in the Registry at slot n where n is this state handle.
The CB is an internal routine to the |
@nwf, re my above comment
I am being dumb, in that in this usage |
One obvious feature of the C API compared to how our module use it is that while many API calls are type I am guilty of this one myself 😟 |
Some modules use "non-public" C APIs, that is other than
What I have done with a few API calls added to support NodeMCU, and which are genuinely part of the public API is to give these a My inclination is to add |
I believe some of the use of You're welcome to leave those offences stand and let them get fixed in time, if you like. In the interest of differentiating "core" and "NodeMCU" lua, maybe name them |
Another placeholder that I want to on record, but one that probably only @nwf and @jmattsson is interested in -- and hence this comment rather than a separate issue.
As an corollary, I note that many users will include a range of modules for their firmware build 'just in case' but then only use a subset for any specific application usecase. Given this, I now think that it is a better practice for ESP applications to do just-in-time initialisation, wherever this is practical, so we should discourage using the initialisation hook. For example most modules have an entry @nwf Nathaniel, as an example of this last point using TLS incurs a high RAM footprint. Is this still the case if no TLS connections are initiated? If so, then this would severely limit the app developer's ability to generate on-ESP LFS images. |
The |
This issue has been automatically marked as stale because it has not had recent activity. It will be closed if no further activity occurs. Thank you for your contributions. |
I've noticed that the current libraries haven't been cut by someone who is familiar with the Lua C interface APIs and as a result the only a subset of the API is used with standard features being reimplemented inline in the library code. A good example is in the
gpio.c
module where:can be better coded:
This is shorter, easier to read and uses less code space.
My suggestion is that it is not worth going though the modules tidying up such loose coding as a separate exercise, but that if anyone is doing material changes to any specific module, then it does make sense doing this tidy up also at the same time if there is a code space saving.
Though given Nick's recent comments, maybe this tidy up is best done as a precursor commit.
The text was updated successfully, but these errors were encountered: