If you take away anything from this article, it should be at least this. Intrinsics/builtins should be your first approach. Only use inline assembly if you can't express what you need using intrinsics.
When writing BPF programs, sometimes it's tricky to get the compiler to generate code that passes the verifier. This can lead you down a path of writing bizarre C in order to try and produce the right order of checks and register allocations.
So, use inline asm!
It's not portable any more... But it's a BPF program! There's nothing to port it to.
It's less readable... Wait no, it's _more_ readable because BPF asm has good syntax and you can avoid the bizarre C backflips to satisfy the verifier.
It's unsafe... Wait no, it's checked for safety at load time!
You can write C hooks for tracing and profiling, etc. - with inline asm!
I used CodeWarrior for PowerPC about 15 years ago, and its inline assembler was very easy to use. No markup required, and you didn't even have to really understand the ABI. Write a C function, add "register" to the parameters, put register variables inside the function, add an asm block inside it, then do your worst. It'd track variable liveness to allocate registers, and rearrange instructions to lengthen dependency chains. Any problems, you'd get an error. Very nice.
The only thing that held it back was the lack of scripting. It was probably a rebound rejection of the MPW days, when everything was script-based (and with a crazy custom language.) I remember thinking that the design team probably didn't want to open that Pandora's box, lest scripting might lazily become required and spoil the UX.
Unfortunately, this made CW unsuited to the advent of CI. Even then, I still think it was stupid for Apple not to acquire Metrowerks. The first 5-10 years of Xcode versions had a worse UX and way worse codegen.
Clang (but not GCC) also supports the MSVC assembly syntax which is derived from Borland inline assembly. Unlike MSVC, Clang supports it in 64-bit mode and also for arm.
(Scheduling is almost useless on modern desktop CPUs anyway, except for some instruction fusion patterns.)
There are quite a few things I reflexively write where I know that in the specific case I don't actually need to do that, but also know that it'll make the code easier to skim read later.
I hate having my skimming interrupted by "is this the case where this is safe?" type situations.
One can, of course, overdo it - and to what extent it's worth doing it depends on who you expect to be reading it - but it can often be quite handy.
A concrete example:
this.attrs = { style: {}, ...attrs }
will work fine if the 'attrs' variable is null, because ...<null> is not an error in javascript and expands to nothing ... but I'll still often write this.attrs = { style: {}, ...(attrs??{}) }
instead because it makes it clear that the code is allowing the null case deliberately and because it means the person reading it doesn't have to remember that the null case would've worked anyway (and also because my brain finds it weird that the null case does work so it often makes me pause even though I well know it's fine once I stop and think for a second).TS only complains about valid operations if there's some potential mistake due to ambiguity, usually when relying on to strong conversions such as adding a string and an array together or some other nonsense.
So I strongly disagree with 2 and 3.