Comments by "MrAbrazildo" (@MrAbrazildo) on "C Skill Issues - White House Is Wrong And Here's Why" video.
-
42:58, you are right, but you are comparing to C. In C++, just make_unique: it'll even dismiss you from having to write another line, as this defer (also avoiding the leak of not calling it) , because its destructor will free the mem., when the time comes (reaches the end of its scope).
43:54, wrong! C instead of C++ is. His use of macro, to help the limitations of C, was well applied. I used to use it a lot, in the past. C doesn't has defer-like, as long as I know.
2
-
10:00, probably is skill vs number of people (average for up to 10). So that 20% are (0.3 / 0.05 = 6)x devs.
10:38, at chess, this graph not only is precise, but also it happens to so many people, that it's not absurd to take it as a "fortune teller" about someone who is going to learn chess.
11:53, I think it's about the same, but removing the vale of despair. This phase and before, probably happens on the very beginning. That's why it's missing here, which intends to take visions from professionals. So I think from junior to somewhat above it, the perception about software quality is optimistic, vs the pessimistic from a senior and beyond.
15:35, perfectly safe C is probably unbearable, due to UBs everywhere. But C/C++ working code, passing good tests (edge cases only/mostly) is achievable fast. Plus, there are awesome tools nowadays, even for UB. So, if development time is a thing, Rust won't be the best choice.
The problem is when a company abuses this fast pace productivity of C++, taking as "lost of time" automated tests, applying tools, writing your own tools. For these scenarios, Rust probably is better - not for the dev., but rather for the bosses: I mean Rust is the harness, boss is a stupid rushing horse .
23:13, C++03 had this, but split: words in the constructor, values here. It's better for dealing with legacy code, since it dismisses us from having to change the initializations.
1
-
31:02, I don't know if this is UB: '(pos) && (n = (pos)->next)'. Compilers use to be allowed to choose which portions of a cmd they want to solve 1st. So if pos == NULL, could it made 1st n = NULL->next?
32:04, just answer: what of those 2 lines would you prefer to write? Directly the big for (uglier and more prone to errors) or the short macro? 32:09, it's just the header of a for loop. There's no way to make that without a macro.
34:00, I stopped using goto like that, as a f() destructor, when I moved to C++.
34:21, as the same way as 1 adds { } to a for, for more than 1 cmd, he can add them here too. So it's not limited to 1 cmd.
35:15, it's more D.R.Y.-ed.
37:30, I use CamelCase for constants. I don't know, upper case seems "frozen" to me.
1
-
1
-
19:05, still about this code. Its returning value is inverted, considering that 0 is false, otherwise true, converted to int as 1. This is in the core of C/++. So this can (and will) cause bugs. I can imagine: if (test()), hoping that the test passed, when it got a NULL! And UB! Ok, sanitizer would get this fast. But let's not be bad programmers just because of that, shall we?
I know that, in ancient C, the 'main' f() got this absurd convention for some reason. And someone could say that this 'test' was made an "entry point", thus trying to follow main convention. But 1st, (at least) C++ has EXIT_SUCCESS/FAILURE, to let us forget about this. 2nd, I'll assume this was just a no-excuses mistake.
So, how to fix it? It's not possible to just exchange those values, since bugs would start to poping-up. If I would alone in this project, I would just create a C-enum, like:
enum test_ret { TEST_FAIL=0, TEST_PASS };
(The explicit 0 is due to 1 had once be the default. So I don't trust enum defaults) . The important thing is to tie the failure to 0 (false).
This would be enough, since I respect global constants. Not just because it's a C++ Core Guidelines rule, but also because I have personal experience about that. People underestimate literal numbers danger.
However, working in a team, it'd has people writing things like: if (test() == 0), and the enum would be implicitly converted to int, generating bugs, if nobody hunt those call and change them by hand. It's what I would do, after the enum.
If they were too many, risking the team write more of them than I could fix, I would change the enum to 'enum class'. It'd cancel the implicit conversions to int, causing compile errors. So people would be forced to see the enum class declaration, and its global constants - any IDE would open its file and location.
Even so, there would be people just taking a glance at it, thinking "Ah, some idiot changed it to enum class, thinking it'll make any difference" . So if I start to see many casts to int, like if (0 == (int) test()), the issue still would not be solved.
Then a more drastic solution should be taken. I would change the 'int' returning type of test to something not declared before:
CALLING_A_MEETING_TO_REASON_ABOUT_THE_STUPID_TEST_RETURNING_VALUES.
Compile errors popping up. The idea would be to stop the entire production line, making the new-feature-addicted boss freaking out, risking my job. But it should be made before this gets out of hand - some decision of not messing with working code. To get the boss hallucinating, could even put the time: MEETING_AT_10_30. He would appear sweating, pointing me a knife:
"Guess what? Nobody steals my job!"
"I don't give a crap about your sh##y job. I'm paid to defend the company goals, which are above you. So I'll keep that, until a get done with this sh##ness, and quit to wash dishes, which is a better job, thus paying more!"
1
-
The author showed good skills, regarding clean and DRY code, automated style (including safety checkings) and knowledge of technicalities about C. But to me what really matters about senior or ace worker is the concern toward safety. He didn't mention this, at least not by words.
19:05, for instance, in this code I would point out some things:
- 1st, I would "rewrite everything in Rust"... Nah, it'd be in C++, which is indeed an improvement over C, not lefting anything behind. If the boss didn't agree: https://www.youtube.com/watch?v=O5Kqjvcvr7M&t=22s
- I would pay attention if linked list would be the best choice. It's only faster when there are too many insertions in the middle - that means a sorted list, somehow. Otherwise, a std::vector-like is much, much faster. For instance, if it's just a database, this sorted linked list would be slower than an unsorted vector-like, adding to the end, and removing in the middle by replacing it by the last. Or am I wrong?
- I would study the idea of changing that boss raw ptr to a unique_ptr or something higher-level: more elegant and safer.
- I would change that person::name, from C-array to std::string: more comfortable to work and almost no chance for UB, leading to cleaner code, since it'd require much less if-checkings by the user. But main advantage is that std::string is not a primary type (it's a class instead). So it's possible to later change it, by a user-defined faster container, keeping the same syntax to communicate to outside - no tons of time refactoring throughout the entire project . This would not be achievable with C-array, unless all its uses/calls where made via f() or macro - which nobody uses to do for it.
And would worry about that only if that std::string was a bottleneck, which is unlikely. But ok, let's imagine the worst scenario: it needs to be replaced by a fixed-size array, which uses to be 20% faster on the heap, only. Since it is not flexible as a std::string, does that mean it'd break its syntax, needing refactoring? Actually no, there's a turnaround: a tiny user-defined class, inheriting std::array (same speed as a C 1), and writing by hand all std::string specific functionalities, like += for concatenating. So all the work would stay inside the class.
In case of bigger name being assigned to 'name', an internal check would be made, as Prime pointed out. But not via assert, which would break the app - it could be 1 of those ongoing apps. Just an if, truncating the name to the size, writing an error to std::cerr.
But probably a fixed-size array could not be used: it has a limit of total memory per app. Since this code is making allocations, it suggests there are a huge number of persons. So it'd get a seg. fault. So std::string would be indeed the best choice.
1
-
19:05, I forgot to mention 1 more thing: I would make person a class, instead of a struct. Compiler would fetch me a list (as errors) of all f()s who interact with the class.
Then I would copy their signatures, putting them inside the public area of the class, as 'friend's. Now, whenever some error happens due to wrong value for any member of that class, anyone would know EXACTLY where to look 1st. Awesome feature! It'd also avoid to change member data accidentally, on other unauthorized f(). Whenever that happens, the programmer would be invited to rethink the design. In my experience, this results in better design and less bugs.
To avoid make unnecessary friends, f()s who only read fields from the class, would not be friend. They would make the read via public getters I would write - but no setters.
1