MarlinFirmware / MarlinDocumentation

Marlin Firmware Documentation Project
https://marlinfw.org
GNU General Public License v3.0
370 stars 780 forks source link

Coding Standard refactoring #166

Closed Sickeroni closed 4 years ago

Sickeroni commented 6 years ago

TL/DR

I read the Coding Standards to contribute code to the Project. After reading it I found (in my opinion) not optimal rules.

abbreviations

the rules

Filenames (optional):

even trough the CCG allows .h [CCG-SF.1]. It is good practice to use differending endings like .hpp or .hh to differential between C-Headers, C-only-Headers and C++-only-headers.

Capitalization

okay but the reason to use camelCase is not valid. Namespaces are there to prevent namingproblems. Thats why we use C++ not C. The Rule should then not allow camelCase but a new rule should force using of namespaces.

Language Features

Primitive Types

First rule is really good. I'm missing it in almost every project! Second rule is is suboptimal. Because of roundingerrors floating point datatypes should be forbidden.

Memory Usage

if macros are forbidden (later in this issue) a static can be annoying with enabled compilerwarnings

-Wunused-function

Warn whenever a static function is declared but not defined or a non-inline static function is unused. This warning is enabled by -Wall.

SRC

Minimize Repetition

Preprocessor directives

we use C++11. #define is the enemy of every C++-Coder.

Macros

Math Macros

same as Macros

Adding a New Feature

i don't want to repeat myself.

Roxy-3D commented 6 years ago

CamelCase has a lot of fans... Myself included. And it would be nice to get rid of floating point just because of the speed issues associated with its use. But we need it for both the precision and the dynamic range of the numbers.

p3p commented 6 years ago

Macros are bad

I'd run while you still can before thinkyhead sees this, joking aside we need Macros and defines in Marlin for the level of control over the build and what code is even parsed by the compiler, in the future constexpr ifs(c++17) could do a much better job (and multiline constexpr function from c++14) but at the moment we are stuck with the evil that is the preprocessor.

thinkyhead commented 6 years ago

While it's certainly important to hear differing opinions on how Marlin should have been coded in the past and how it should evolve going forward, it's always better to have the actual code changes submitted for evaluation as pull requests so we can see the results and whether they keep the code lean and fast for the sake of 128K MCUs. Simply saying "this and that could be better" is unlikely to get us to stop the presses and rewrite the existing code when we have so much on our plates. If you have good ideas, join the project and help make the needed changes.

Sickeroni commented 6 years ago

CamelCase has a lot of fans... Myself included. And it would be nice to get rid of floating point just because of the speed issues associated with its use. But we need it for both the precision and the dynamic range of the numbers.

  • i understand the need for dynamic ranges but the where do we need this? bigger printers need more steps? that is known at compiletime and then we must use something ugly like a 64 or 128bit integer. That should be still fast enough compared to Floats.
  • on the other side we dont have that precision on floats. [source] (its easier to copy this proposal with its explaination on this topic)

I'd run while you still can before thinkyhead sees this, joking aside we need Macros and defines in Marlin for the level of control over the build and what code is even parsed by the compiler, in the future constexpr ifs(c++17) could do a much better job (and multiline constexpr function from c++14) but at the moment we are stuck with the evil that is the preprocessor.

I don't understand why if constexpr()is the solution here. Its only helping if only called elements exists. Because i can't explain it that well here some code:

extern int x; // no definition of x required
int f() {
if constexpr (true)
    return 0;
else if (x)
    return x;
else
    return -x;
}

[SRC] constexpr variables and optimization like -O1 are enough. (Arduino IDE uses -Os) proof in Godbolts Compiler Explorer

While it's certainly important to hear differing opinions on how Marlin should have been coded in the past and how it should evolve going forward, it's always better to have the actual code changes submitted for evaluation as pull requests so we can see the results and whether they keep the code lean and fast for the sake of 128K MCUs. Simply saying "this and that could be better" is unlikely to get us to stop the presses and rewrite the existing code when we have so much on our plates. If you have good ideas, join the project and help make the needed changes

My intention here was to see the feedback on this topic. If people have complete different opinions on solutions and problems, they cant work together. I just don't wanted to hear "nah we dont want it your way. We love the old one" after working for weeks on changes and my code will definitely break the coding standard of this project.

p3p commented 6 years ago

I don't understand why if constexpr()is the solution here. Its only helping if only called elements exists. Because i can't explain it that well here some code:

It's a solution to having preprocessor like capabilities in the compiler, constexpr ifs can be a 'replacement' for preprocessor ifdefs, they allow the same precision in what code is actually compiled allowing for the architecture and feature specific code paths that Marlin needs while being able to use constants rather than definitions.

Marlin is very reliant on the preprocessor at this point, I don't like that, but I understand why it was designed that way at the time, and how fundamentally intertwined it currently is but if you could remove the preprocessor usage from Marlin and maintain binary size and performance across all architectures and configurations while allowing us to do runtime configuration on the more powerful boards I'm pretty sure we would all be very happy.

thinkyhead commented 6 years ago

If people have complete different opinions on solutions and problems, they cant work together.

Everything is mutable. I wrote up the coding standards because there weren't any, and the code style was all over the place. The intent was to formalize the de facto standards which were already prevalent in the codebase and to have something we could refer contributors to instead of having to reiterate over and over.

Since we actually work with the codebase every day, we're hugely aware of its shortcomings, but there are only so many hours in the day, and we have a lot of things on our plates just patching up existing issues, implementing feature requests, and trying to move on from the 1.1.x codebase and get rolling with the unified 2.0.x codebase.

Much of what you suggest is already very much on our minds. We've had a lot of debate and discussion around these things, but as it takes time away from the work we really need to get done right now, I will keep insisting on less talk and more action.

That said, let me briefly go over your points with some first impressions…

So anyway, you're not the first (and I'm sure won't be the last) to point out all the things we wish we had done yesterday but (due to the linear nature of time) have not yet gotten around to doing. If you look back on Marlin 1.0.0 and follow its evolution over the last 5 years you will see that a huge amount of work has gone into establishing some basic standards, cleaning up the code, trying to make its patterns more evident, and waiting for Arduino IDE to catch up and allow the use of C++11 features. Right now we are at the very tail end of a two year process of molding the 1.1.x codebase into a final form so that we can move on and get into architectural improvements. I've personally wanted to rewrite all the LCD code for over a year, for example, but simply haven't had the time and space to delve into it.

If, as it appears, you would like to help us to modernize the code-base while also keeping it lean and performant, please get on board and start making iterative improvements to the bugfix-2.0.x branch. We will evaluate them on their own merits and accept any and all that make clear improvements. Just, please, don't be one of those people who is always pointing out how stupid things (and by extension, we) are.

thinkyhead commented 6 years ago

Here’s the video I was thinking of, apropos to this topic, that every Marlin developer should watch. Using C++17 (and in some cases 14 and 11j to write code that compiles with the least possible overhead, even when using the stdlib. The example used is a Pong game on the Commodore 64, with intermediate compilation to X86 Assembler. This is the video that got me using const to an obsessive degree, certainly more than is necessary, to help the compiler optimize wherever it can. In particular the use of a const std::array in the video has a dramatic effect compared to a non-const instance. (And with C++17 a constexpr Instance will also be possible.)

https://youtu.be/zBkNBP00wJE

Roxy-3D commented 6 years ago

.h versus .hh or .hpp. I'm pretty "meh" about this, since I would prefer all the code within the Marlin folder to be under C++ semantics, but if it helps the compiler

.h is fine for both C and C++. There is no reason to do anything different.

Floating-point: We'd like to use fixed-point for some stuff, but sometimes it's better to use float. Anyway, converting everything away from float is a huge pile of work that simply no one has volunteered for.

Soon, with 32-bit platforms we can just declare everything as double. I'll take that over fixed point.

Avoid #define: We're not going to change all the configuration files to use constexpr in place of #define at this stage.

Agreed...

Includes and #pragma once: Sure, now that we can use #pragma once, great, let's use it everywhere we can! We also like to not-include headers (by feature) and in many cases not-compile whole .cpp files (by feature).

If, as it appears, you would like to help us to modernize the code-base while also keeping it lean and performant, please get on board and start making iterative improvements to the bugfix-2.0.x branch. We will evaluate them on their own merits and accept any and all that make clear improvements. Just, please, don't be one of those people who is always pointing out how stupid things (and by extension, we) are.

crickets???

thinkyhead commented 4 years ago

Soon, with 32-bit platforms we can just declare everything as double. I'll take that over fixed point.

With many (if not all) of the ARM chips, interrupts cannot use the FPU. So, fixed-point would still be optimal within the stepper ISR and other interrupt contexts.