3 ms·
> In this session, learn some of the best practices that every C++ programmer needs to ensure successful completion of a project. I find it annoying when peopl
by jbotdev 3y ago
> In this session, learn some of the best practices that every C++ programmer needs to ensure successful completion of a project.
I find it annoying when people say you “need” some best practice. The things you actually need are generally enforced by the tools (compiler errors in this case?). Everything else is subjective and/or depends on your use case.
- Yoric 3y agoI would disagree. In most programming languages, compiler errors and even linters lag by orders of magnitude behind the practices that will actually let you write code that stands a chance of being safe and secure. I haven't looked at this specific list yet, but I am yet to see a C++ project in which code works just by following what the tools tell you.
- bluGill 3y agoI find tools are very helpful to reminding me of rules I forgot to apply, but they can only detect a limited subset of places where I forget to apply tools.
- jbotdev 3y agoMaybe I’m arguing semantics, but my point is “need” seems a little subjective here. You can write insecure/unsafe/unreliable code and it’ll still run and compile just fine. You probably don’t want to, but you don’t “need” every program to be safe.
- rerx 3y agoThat's not trivial, in particular with C++. However, the talk actually talks about setting up tooling as early as you can as a best practice, like multiple different compilers or regression test suits on all targeted platforms.
- tialaramex 3y ago> The things you actually need are generally enforced by the tools (compiler errors in this case?). No. This is specifically C++ which has IFNDR ("Ill-formed, No Diagnostic Required") which means the ISO document says there are things (a lot of things it turns out, WG21 appears to have given up even trying to enumerate them) which aren't valid C++ - and so you mustn't do them because the resulting program is meaningless - and yet the compiler isn't expected to detect them and reject your program. Henry Gordon Rice wrote an important PhD thesis about computation in like 1951. Rice's Theorem says that all non-trivial semantic properties are Undecidable. But we want semantic properties! So, if your programming language is going to have non-trivial semantic properties then you have two practical options: 1. Accept all programs which may have the desired semantic properties, since you can't always decide which those are, you give up and accept programs where you aren't sure, these programs are nonsense, but too bad. That's C++ with IFNDR 2. Reject all programs which may not have the desired semantic properties, since you can't always decide which those are either, you give up and spit out a compiler error when you aren't sure. If a program is rejected maybe the human programmer will rewrite it so that it's acceptable, which is a burden on them. That's what Rust does.
- deleted 3y ago[deleted]
- AnimalMuppet 3y agoCould you give a concise example of IFNDR in C++? I'm having trouble picturing what that would look like.
- tialaramex 3y agoThe most classic example of IFNDR is ODR the One Definition Rule, which goes like this: In the final C++ program, there can only be one definition of any particular thing, however, C++ is actually built by taking individual source code files and just pasting in stuff (using #include) and when you do that, obviously you'll often be defining the same stuff, each time. So, what if the definitions are different? For example maybe when mainprogram.cpp is compiled, the variable max_princesses is defined as the literal 10, but when the princess.cpp file is compiled, perhaps several minutes later, the variable max_princesses is now defined as the literal 0.5 - that's not even the same type! What happens? The ODR means that's IFNDR, so instead of C++ needing to somehow guarantee that this definitely is caught by compilers [these days some compilers will catch some ODR violations but it's not all of them and not always] the standard just says too bad, that's not a valid C++ program so whatever it does is your problem. A really shiny modern example of IFNDR is C++ 20 Concepts semantic requirements. See, functionally C++ 20 Concepts are just syntax matching, but their names imply semantic value, the standard says they do have semantic value, but it's not actually enforced by the tooling, so syntactically float (a floating point number) matches the concept std::totally_ordered - but of course floats aren't actually totally ordered, that's silly. How do they square this circle? IFNDR. Using a type which matches the syntax, but doesn't fulfil the semantic criteria means your C++ program is ill-formed, but the compiler wasn't expected to tell you about that, your program is just gibberish, it might do anything - after all, floats aren't in fact a totally ordered type.
- AnimalMuppet 3y agoThanks. So of your two examples, here's what I would expect. In the first one, I would expect that either everything would work, or I'd get a syntax error, depending on which definition was actually used at the time I compiled the line in question. Are there examples where anything else happens besides those two options? (OK, I guess there's also the option that two different compilation units have two different definitions at the time I compile them, and then I link them together. Best case the linker catches it; worst case I'm doing floating point operations on what is sometimes an integer variable, and I can see some very weird things happening from there.) And in the second example, I'd expect everything to work right up until I tried to sort (or whatever) the floating point numbers, at which point it would either work, or fail to sort, or infinite loop, depending on the exact floating point values that the program was operating on. Here I could see there being other options, depending on exactly what the program was trying to do, but not dramatically different. And, would it do anything but work as expected if there were no NANs or negative zeroes or something exotic like that? That is: Despite the "it can do anything" statements, in practice, with production compilers, does it do completely unreasonable things? Or does the "anything" it does have some reasonableness to it? Yeah, I know, I'm not guaranteed that. In practice, I don't actually care how my code might break on Windows 3000 with its new 197-bit bytes. I care some about problems on platforms and compilers that it's reasonably likely to need to run on someday. (I'd care more if I were writing library code, and even more if I were writing code for the STL. But I'm not, and while portability is desirable, it's not the only input to decisions.)