Comments by "MrAbrazildo" (@MrAbrazildo) on "ThePrimeTime"
channel.
-
1
-
7:12, this guy missed the point that companies wet dream is to hire juniors only. This is a goal, but hasn't been possible so far. It's predictable that some of them would eventually ask, for its top programmers, to develop a language/library to help noobs.
14:06, you should, because otherwise it's prone to erros: similar blocks of code put your guard down, while a bug is hidden between them. But there are some caveats for that:
1) Copy-paste is good practice, due to saving energy, which will be important on the long run. I even timed that once: it took me 20h to create 1 bug due to that, meanwhile I saved energy many times.
1 just needs to be a bit more careful when doing that, compared to normal code. And soon being ready to make the number 2:
2) A common code for all repeated block. Not with ifs between them, which leads to bad performance, due to branches. Just the actual common code should be extracted.
14:36, nice statement. Is it yours? I heard that for performance, but now that you said that, it seems more real for abstractions.
22:28, if a language lacks encapsulation, it's over to me.
1
-
12:00, the standard is conservative: keeping a language with "all features" is already a lot of things. And since it aims to have backwards compatibility as much as possible, it's desirable to keep off things that seems to be "born to be external" tools.
I guess this view of not breaking things along the way allowed the language to exist, with success, for so long time.
12:14, chat: its syntax is a war crime. I find it to be quite clever: it's productive, since you type 1 thing, and it's likely to be correct - the context will tell exactly what it is. ie: you don't type defaults, saving energy - what would be an error, it's allowed under a certain context. I don't know how many languages have 'var' and 'let', but this last 1 for constant is stupid: it should not exist (const as default).
12:36, it could be worse: forced to use identation.
19:19, you can only be joking. With a bit of effort, C++ jumps to a kind of high level language. 19:55, for instance, when 1 makes an algorithm traverse from [begin; end), the pointers are always trapped. I never got a memory seg fault using that! Ok, only 1 time I fell for the "invalid pointers", when the memory was reallocated. But never again! And it was an easy to catch bug.
1
-
39:53, it's comparing the addresses they are pointing to, which should be y's, if x and y are in this sequence.
41:50, 0x7fff'ffff + 100 is UB, invading the bit for the sign area. The right way to write that check would be: assert (0x7fff'ffff - 100 >= a); And I guess the standard <stdint.c> lib has INT_MAX (or alike) constant for that max value, which should be used instead.
Plus, there's an UB on main too: not returning an int, when promised that. However, there's a compiler flag to catch that.
46:00, it's broken, because an UB was created BEFORE even the check for UB was complete! 48:35, precisely. 53:49, I disagree, because it's inflicting the compiler's freedom. Let's say a compiler deploys signed 32 bits represented as 31 bits, with the signal being kept somewhere else. This unnecessary way of checking might create unnecessary problems.
1
-
1
-
If this engine is for game, don't do it. Instead, make the game directly, only what is needed for it. Whenever something becomes generic enough, put it in a general lib of your own. In far future, if this ever becomes robust, only then you make an engine out of it.
I strongly recommend C++, or at least its classes and containers (from STL), to properly hide data. Game is a wild environment, eager to steal your data, which needs to be tightly secured.
1
-
@anon_y_mousse Games have a loop, having to keep values memorizes. So, goodbye to pure f()s ideal world, for instance. There are plenty of side-effects, often. It also takes important decisions, like which branch to go, according to those values.
So it's needed to avoid some unwanted f() to "steal" some data (to have access to it, when it shouldn't) to change it. If everything is public (global variables, for instance), lots of things will be changed at wrong moments, either by mistake or by a "4am hacking thought of design" - a "theft of data", compared to good design.
1
-
1
-
1
-
1
-
1
-
1
-
1
-
7:36, I'm huge fan of macro. I think it even should be expanded, being more powerful. But of course, if something can be made without a macro, go for it. For C++, typedef (nowadays "using") provide alias for types, lambda works as private f() within a f() (something that I want for long). All of that work as encapsulaters for technical stuff, letting us to think the code in a more high level way. Macro can do this, even joining pieces of code that wouldn't make sense otherwise.
For those that don't like the plethora of things like that that I write, I just say: their definitions are always either in a) Right above the current f(), b) Above the current file, along with its global constants, c) In a global place of the project files. That will depend on the broad of its meaning.
On IDEs like Codeblocks, just leave the mouse over the alias/macro, and it'll show its meaning. Or right-click over it -> Go to its declaration, after a recommended Ctrl-B, to mark the current place to go back later, with Alt-PgDowns, if the declaration is in the same file.
1
-
29:24, I agree, but I would never rewrite STL because of that. My f()s and classes use to not be generic, whenever possible. For things coming from STL, I use typedefs.
30:15, this is a Java thing. Well coded C++ use friend keyword, to allow just a few f()s to access nonpublic data.
31:43, std::stringstream is just a higher level scanf. And faster, according to a measure I took. I would only argue against it if performance was at stake on it: pointer, for instance, is much faster. It's syntax is not ugly to me. And std::to_string does the trick, if this is the only reason of using this stream.
32:25, 1 line f() could fit inside the class definition. And using std::clog, to not be generic, would dismiss receiving ostream and another class too. Result:
auto show_val ( ) {return std::clog << val;}
Plus, even using the overload, it could be made via:
std::clog << "blablabla" << object.get_val();
I think the code in the video is beautiful, if 1 desires what it offers: throw strictly the object (not 1 of its members) to an object that is or inherited a std::ostream. What is stupid and ugly is to write a f() like that (in the video), when 1 would be satisfied with the already existing 'std::ostream::operator << (int)'.
And printf is better only when several values are being read at once - otherwise it's less productive, due to type specifying ( + warnings) and demanding more typing on keyboard. So their thesis of condemning streams fell flat.
35:25, I have a tolerance about 1 line f() definition (below its header) inside class definition, because I can still put { } on the same line. For more than this, if { } is used normally, it starts to push the code downwards, looking noisy to me.
I also try to align returns, f() names, 'this' specifier, and f() definition, whenever they are "attached" (1 right below the other). Of course, I don't put these many stupid unnecessary spaces between the "fields". (35:39, giggles)
About the horizontal look, it's ideal for eyes, since they are widescreen. Code is ideally meant to be looked by eyes, not with help of hands, unnecessarily travelling vertically.
1
-
36:20, I think dismissing 'get', just 'length', is much better because it works accordingly to the Polymorphic Principle: "1 interface, multiple methods". The object (the "interface") is giving the context, so length refers to it (as well as the other f()s/"methods") - its size, in this context. Code is also assuming a default here: whenever the action is not specified, it means just the word (it's value, probably). I believe assuming defaults is a good idea, taking advantage of typing less, speeding up communications, saving energy, and so on.
Btw, 'size' is a much better name, because it's shorter, more broadly used (by STL, at least) than 'length', which confuses foreigners about th vs ht.
The only downfall for a direct name is that 1 probably has a private variable with the same name. Some people use a '_' suffix, which is kind acceptable, but not a tradition yet. So the solution may look a bit annoying.
38:09, good thing showing the footnotes. You should do this in all videos.
41:13, no, damn it! It's helping you to fix the BS you were about to do!
PS: Diablo 1 has the better source code I saw from games. It avoids vertical code most of the time, it's simple at all. However, I spot 2 flaws: literal numbers and other that I don't remember right now.
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
-
1
-
1:28, to avoid forget to close (, {, [, I kept the option of automatic closing them, right after I opened them. The same for return instruction: whenever I start writing the f() header, I put the return right away. Other solution is to declare the returning type (at left of the header) as auto.
1:30, I only use C-array when it's const an already initialized with values, that I'll access through enums. At this case only, it provides advantage over C++'s, due to shorter notation. Otherwise, I always use this last 1.
2:11, this includes building defensive tools, to make it safer, far from its default.
3:20, I'm learning to use MQL5 for finance, and they use a C++ inspired language, more defensive by default. I also heard about some people using Java, to make often changes with less risk. But I heard too, in a presentation, that "C++ is the language of choice on this subject" .
5:50, once 1 get used to those, they become easy to manage. If bug happens, it's no more hard to find.
8:53, I heard C++ is starting to replace C on there too.
11:47, since I don't like to configure compilers to attach them to code editors, I only recently got the complete C++17. In Linux, I finally get C++20. Android is barely at C++14, at least with SDL dialog to Java JNI.
The good news is that, to become massively more productive, just C++11 is needed, and, for a few blasting features, C++14. C++17 (and I guess C++23 too) is weak, but for C++20 it's said that it's the new "changed our way of coding" .
12:57, it abstracts the low level by default, it's middle-level, and can jump easily to high level, if 1 develops his own classes, working exactly the way he wants and the project demands.
13:03, all of this from C++11. Lambdas are nice: I just type [ ( { (, and end up with [ ]( ){ }( ), completed by the IDE, which is the hard part. Or I can just type lbd + Crtl-J, Codeblocks will expand this according to an abbreviation I previously wrote, that could be like that 1 in the video. To avoid conflicts vs the capture, just type [&], and it'll capture everything as a mutable reference, also dismissing having to receive f() arguments.
1
-
14:08, there's a way to get rid of all those if checks, safe and easy that even C can handle: get a file only to handle the nodes chain/tree. There, some private content will handle the control over the nodes. For public access, only public setters. (This is 1 of the cases this FP approach can enjoy the same safety level from OO. It only evens because those setters are supposed to be called from anywhere) . So the use would be like:
create_node(); // Let's assume it failed. Optionally, an err msg could go to some log output.
goto_next_node(); // It automatically checks the next 1's validity, thus doing nothing. Another err msg to log.
int a = read_var_A();
// Validity check is made here too. Since there wasn't a "next node", it'd return variable from the current 1. But since the list is empty (automatically checked too), a literal value would return. Log should report all of this.
goto_previous_node(); // There's none, so it'd not go anywhere.
So, this is pretty safe. Log could even get better, by using a trick I saw in a Eskil Steenberg's video: each of these f()s could be a macro call to their actual versions. i.e.:
create_node_ (__FILE__, __LINE__); // It'd call this behind the scene.
By reporting the current (at the calling moment) _FILE_ and _LINE_ to log, it'd not matter how large the project would be, the exact location of the error or missing explicit check by the user would instantly be known, making debugging tremendously easy.
The price is that, despite the code would be clean of explicit checkings, the generated bytecode would has lots of implicit checkings, leading to much more branches, thus slower code. But this is easily fixed: once the app is safe, follow log's instructions about locations, adding explicit ones. Once no more of those err msgs appear, just change 1 macro line, which controls whether or not the implicit checkings are compiled. And then recompile the whole thing.
1
-
6:33, hehe, Codeblocks is like that: a mid-term, not as fast as Vim, hasn't all its vertical moves, nor all InteliJ features. But I like to think it has the best from both: it's fast and light enough, doesn't require previous study, just install and run, opens in some seconds (ok for me), doesn't erase things I wrote, has plenty of IDE famous features, and I can also edit them. I move fast on it. It's what really matters to me.
1
-
1
-
4:13, this is strange. If it's maintainable, it means above all things that it hasn't UB (thanks mostly to the high level language you are using) and that it's not changing variables on wrong places as well right places too, in different f()s (well structured).
But if it's good on this, it should be prone to be readable too. If I would risk a guess, I would say some variables are been changing on wrong places only, damaging the meaning of things (strategic view). 5:43, this may endorse what I'm saying: the goals of each f() were properly defined: they are mixed. Some f()s are doing job of other, when they shouldn't. 6:05, my "giant" f()s use to be 5 screen sized. They have a preparation of data (that only makes sense if used internally) to be used later, so this takes space. Strategically, it's easy to see: preparation 1st (2-3 screens, let's say), a main loop later, processing them. I keep things inside the f() due to encapsulation: I don't want the rest of the project having direct access to that functionality, since it would not make sense.
But if the f() was long enough, making me start to forget what was done earlier, even strategically, then I would start chopping it. I would make a class, having the f() as public, and several other f()s private, as its internal content. No way I would let it with 200 lines, if I would start to loose understanding over it.
6:23, the problem with FP is that it's too optimistic about its safety. For example, to work with multimedia I like to use SDL2. It's pure FP. So I get some of those things, that no alien should mess with, and I put in classes. So I think in case of confrontation, OO should force FP to adapt, because it brings issues to code safety.
1
-
1
-
3:15, I can't, there's C++.
7:25, it's better to separate resource/muiltimidia from the logic the commands them. Because resources can be large, staying on the RAM/heap memory, while the logic goes to CPU caches, becoming much faster. I use to let a class hold images, for instance. Whenever wants to draw, it's send a number/code, meaning a request for some specific image. This also avoids unnecessary duplicating resources, since they will stay in a single instance class. I also avoid making unnecessary classes. I only create them to defend critic data, since this is already built in the C++ core.
8:30, the same thing is applied to situations where an object is about to be unnecessarily duplicated: keep things in 1 object, which should receive request to access/modify its content.
15:00, these are not good examples for classes, they could be just f()s. Drawing and saving are actions, classes are mostly for data. Class is recommended for when data must travel safely along the battlefield. Safely means only changeble by authorized f()s.
1
-
1
-
10:54, I agree about the spaces, because they actually aid on visualization. But it's better to not put { } whenever possible, due to "clean code": less typing, faster compilation, saves energy, visually better. The only drawback came with macros (C++ example):
#define my_pairXY(fA, fB) int x = fA(); int y = fB() // Dumb code. It should be int x = fA(), y = fB()
for (blablabla) my_pairXY (getX, getY);
And then y slipped away from the for! But everything has a price to pay. By my experience, it's worth.
12:29, that's my dream. I'm forced to be C++ lawyer, because modern languages are too dumb to take its several good ideas and improve over it. So, with that mindset, nothing better seems to be appearing for the next... decades? I guess I'll take a deep look into Lisp.
13:07, probably means 'obese'.
1
-
1
-
1
-
1
-
1
-
1
-
1
-
6:00, yeah, choosing (what's likely to be) a correct data structure should be the starting point. And this is 1 of contiguous memory, like std::vector in C++. Because a mistake here will take too much refactoring later. On the other hand, algorithm is something that, even if is entirely wrong, 1 will has to change mostly inside 1 f(), not scattered parts throughout the project.
9:05, OO is so flexible, that 1 can inherit that class, and implement his version of some functionalities, not changing it.
10:29, I guess "Dave's Garage" (ex-MS) channel revealed who the guy was, in his series about this algorithm.
11:11, precisely. I made a small game that fit entirely in L1 cache (64 KB for the logic, not resources), after compressed in bits several variables. I spend less than 10% of developing time optimizing it, which led it to 30x faster. And even so, I wrote classes and abstractions (not interfaces) all over the place. It's maintainable, easy to catch bugs, even after not seen it in a while. And it's readable, due to enough abstractions.
25:20, there's a quote which says "Who works with a hammer tends to see the world as a nail" . He wants to say "use the right tool for the right job" .
1
-
1
-
1
-
1
-
0:59, no fun? It's awesome!
10:33, I watched a presentation in which some dude said his team failed badly with Haskell. And if we add to that the Haskell motto, "Fail at all cost!" , we can assume many had tried... and failed badly!
I can imagine why: there's an obsession about pure f()s. The real world needs don't embrace that, most of the time. So 1 has to update variables outside the already precarious encapsulation of a f(), to fulfill the side-effect needs, so avoided by the language. Thus, everything becomes periculous. The disaster is just a matter of time.
12:50, what does that mean? Once you used htmx, you just use it, without an opinion? The perfect pragmatic tool?
1
-
@digitalspecter If variables should not be created, everything could be pure f()s. But there are reasons why things once obtained should be memorized: either performance (expensive to get them again), tied 1 to another (need to be changed together), and so on.
Depending on the project complexity, there's not much space for pure f()s. i.e. if you turn the head of character in a videogame, changing his angle of view, even if not changing anything in the game, variables x,y,z need to change in some place, and memorized, because they'll be asked later.
Now imagine if you split the f(), which calculate changes, to make it pure, letting the variables attribution for another place. So we have the calculating and the changing f()s:
Pros:
- Code become more conceptual, where more actions have a name.
- 1 can shine in Haskell community, by making more elegant code.
Cons:
- Looses encapsulation: things that could better fit in 1 f() are now scattered in 2 or more f()s.
- Harder to debug: more places to look. It's needed to look the production of the value (pure f()) and also the attribution. They should be 1.
- Even worse: the rest of the project can now see and call those new f()s (btw, C++ allows the user to forbid that) .
I'm not advocating to have less f()s. But create them just to feed the Haskell utopian idea to has a "pure project" is bad, dangerous, even prone to disaster!
1
-
3:20, it's political, because the language is being condemned by things it almost got rid of. So he's saying that they should implement those safety measures as frameworks, instead of the already existing external tools. Because otherwise people go to Rust and alikes, and once other codebases grow with those languages, there won't be place for C++, outside its giant legacy codebases. It'll be the new COBOL! An undeserved destiny for the best language!
8:07, it looks contradictory: the language always was made unsafe (for performance) and always aimed safety, as a long term goal. It has a conservative way to see things: it wants to evolve, without sacrificing things on the way. I guess that vision is correct, for its ambitious goals. And having this in mind, the language has indeed evolved quite beautifully, in my opinion.
10:22, that's because he was wrong. People are too enthusiastic over Rust, at the point of misjudging C++.
11:31, Clang compiler launched a 'modernize' tool, that rewrites old working code to new standards.
1
-
22:36, C++11 also had for range loops: for (myType &value: vector_of_type). But I kept using the old for, through a macro like: myfor (it, vector_of_type), because I felt counter-productive to have to specify the type used by the container. I only embraced for range loops in C++14: for (auto &value: vector_of_type), using auto to kill that faulty feature.
25:02, I disagree, because these things are keeping themselves generic enough to work with any type. And everything is separated by scopes, that's why so many :: operators. C++ even has a kind of dry syntax, compared to how many things it's handling on those libs. 1 has to compare beauty to what it's trying to achieve.
27:00, macro can clean this code. While the lib has it in its generic form, to hold all possible user configs (and I think it's beautiful, because it achieves that, with likely minimal syntax) , the user don't need to do that. If it happens to has several arguments, just make a macro or typedef about its meaning:
#define ParamsForHashDecl typename KeyType, typename ValType, // ... the rest.
#define ParamsForHash KeyType, ValType, // ... all the rest.
using ProjectsOnlyHash = HashTable <ParamsForHash>; // Alias.
Since this is made only 1x, similar f()s headers would be like:
template <ParamsForHashDecl>
const ValType &ProjectsOnlyHash::getValue (const KeyType key) const;
getValue is a function from the class 'ProjectsOnlyHash' (1 doesn't even need to read its template args) , that receives a KeyType (that can't be changed) and returns a reference of some ValType, which can't be changed either. The f() also can't modify data from the ProjectsOnlyHash class, except those declared as 'mutable'.
At any time throughout the project, if the user wants to remember what is ProjectsOnlyHash, or its template parameters, just leave the mouse over the respective word.
1
-
14:09, this is good, not an issue, because it'd result in less refactoring, if changed, leading to more productivity.
14:20, 1st of all, this isn't real-life example. std::vector is a pretty fast data structure, that auto-manages its size internally. The compiler is so smart in optimizing it, that I often see it rivaling fixed size arrays.
14:47, I use msg or msn, to keep same letters as in portuguese.
15:00, what are you using? Vim? (kidding) :goodvibes:. On modern IDEs, Codeblocks for instance:
a) 1 can just leave the mouse over the f() name call (cursor not required), and 1s later it shows the f() signature.
b) Right click (on f() name) -> Go to declaration: it opens its header file, right at the f() signature.
c) If nothing of that worked (mostly due to not filling a cache yet) , add an absurd parameter on the f() call, and recompile. Compiler will say: this is stupid, look the f() signature: it opens a small log window from below, from which you can already see its signature, or left click on it, to open its file.
d) Write a tool: got_message could say what it changes, whenever called:
#ifdef SAY_WHAT_YOU_FUNC_CHANGES_WHENEVER_USER_DEFINED_THIS_MACRO
printf ("got_message changes size");
#endif
Then, on a click of a finger, 1 can disable this on the entire project, by just changing 1 line and recompiling it.
16:07, true, but I think the team should agree on defaults, before even start the project.
1
-
0:13, C++11 is the "must see" 1. From that, only minor good features have been made. C++20 is now a game-changer, but it's more related to high level features than performance or middle-to-low level functionalities.
0:38, oh... really nice to know that.
2:51, this is what I believe C++ is able to achieve. But that's not its default behavior. 1 should go (sometimes struggle) for it.
7:43, maybe because of its complexity, it feels solid among the complexity of a project. I was making 1 in 2 steps, the 2nd "as a superset" of the 1st. I basically inherited all the 1st step as basic classes for the 2nd. It worked amazingly! Of course I had to amplify things, but no extra problem was added by that. And the classes were organized by data, not so much by meaning. Even so, the whole previous meaning worked for the 2nd, and no performance penalty was added, beyond what was inevitable from more work to do.
9:40, delete all of them, letting the compiler pointing you the missing ones.
1
-
2:48, they just gave a name for a thing that has been made in C for decades:
struct CheeseBurger { const char *ing_1, *ing_2, *ing_3 };
#define createCheeseBurger CheeseBurger { "bun", "cheese", "beef-patty" }
And then call it by:
CheeseBurger a_cheese_burger = createCheeseBurger;
5:20, this is a "lesser version" of C++ for 2 reasons:
a) If 1 just wants to customize the initialization, C/C++ way is much better, as exposed above, due to compact syntax.
b) If the goal is to customize it along the way, not only on initialization, it should has a control of which f() is allowed do that - and it seems that only C++ has this feature . Otherwise, all sorts of bugs can come from it, because everything will be public, which is the worst nightmare, depending on the project complexity.
10:57, why use an interface for that? Couldn't it be just a class? 16:00, again, why an interface? This thing is awkwardly slow!
21:00, and that's why f() programming < OO: the 1st lacks good facades. In C, you can let that memory management "encapsulated" away in a different file. But there are issues:
a) Each file like this will be dedicated to each object, which hurts scalability.
b) If only 1 generic file like this is created, then the user will has to keep traveling alongside with that array, which is exposed to dumb mistakes for long unnecessary time.
It's still possible to create several macros, trying to hide that array exposure, but it's still a precary solution.
1
-
1
-
1
-
1
-
1
-
8:35, I agree. But I don't know if debugger is overkill. I use to make unity tests. Maybe some prints. This solves +95% of everything. If bug persists, which is rare, I also use a technique I created, called "hacking the solution": I change the code a little bit, test, see results. Then put things back, repeating the process in a different way. This puzzle points me to the right direction.
10:02, I do that too. I think TDD is a bit invasive, when I'm developing the f() signature: I still don't know exactly what it should receive/return, so I want a bit of a freedom. As soon as this is established, I write the tests. Once both are made, the rest of the f() development/fix can reach a pretty fast speed, as it becomes oriented by the tests.
10:10, but I never delete test, unless it can be replaced by 1 that tests what it intended to, in a more edge case way. C/C++ also allow conditional compilations, including or not the tests. So their presence can be configured by changing just 1 line. 17:27, the same thing happens with all those asserts: if #define NDEBUG 1x before, all of them suddenly disappear. So the programmer is not condemned to their presence.
17:53, and compilers evolved too. I saw more than once std::vector (variable length size array) being faster than a fixed size 1!
19:30, it's possible to write tests that just emit reports/logs, showing errors, but not shutting down things.
20:18, I'm too. But I'm 2 workplaces on Linux because, when in development environment, I don't want other minimized windows annoying me, from the rest workplace. I also use the Cube, to give a nice effect when switching between them.
24:40, 1 of the reasons why I use Codeblocks IDE is that because, either on Windows or Linux, I just install (1-2 minutes), pass my pre-configured archive (some minutes maximum), and I'm already coding, with everything I want.
1
-
1:10, does anybody can explain to me what's the logic in calling enum a "sum type"? What's a sum type btw? 1:26, isn't std::tuple enough? 1:53, it's more comfortable than structs, due to possible accessing members via indexation. But I don't use it, because it generates too much assembly code, which leads to slower code.
2:00, are you sure? I know that acquiring/freeing resource are, and this is the main (and should be the only) goal for smart pointers. But raw pointers/iterators are pretty fast for memory accessing. All STL algorithms demand to use them (a few times as references).
4:58, but I'm, and I say it's the best language for crafting tools (more functionality/freedom). Whenever I face something risky around the corner, I build a tool to deal with that.
6:50, you can put declarations and definitions on the same header. I do this for small projects.
7:25, there's no issue about the private data being on the header file. It'll continue being forbidden for public access, unless otherwise expressed.
8:55, I rarely forget to type const. But I agree that const by default is useful. However, it's possible to create a convention for the team:
1) Create some prefix/suffix meaning const for the type, like 'int_'. 2) Do the same for 'mut'. 3) Config. to highlight them in the code editor. 4) Config. to NOT highlight the conventional types in the code editor. This way, the team will notice, at once, that something is wrong when they type 'int', and it doesn't highlight.
10:20, I think const_cast is always a mistake. There's an optimization the compiler does, by exchanging all const by literals, since the beginning, which might colide to that. Better is to go right away to the f(), fixing its const-less issue.
1