Skype was written without exception handling and RTTI, although using a lot of C++ features. You can write good C++ code without these dependencies. You don't use STL but with cautious use of hand-built classes you go far.
Today I wouldn't recommnend Skype built in any language except Rust. But the Skype founders Ahti Heinla, Jaan Tallinn and Priit Kasesalu found exactly the right balance of C and C++ for the time.
I also wrote a few lines of code in that dialect of C++ (no exceptions). And it didn't feel much different from modern C++ (exception are really fatal errors)
And regarding to embedded, the same codebase was embedded in literally all the ubiquitous TVs of the time, even DECT phones. I bet there are only a few (if any) application codebases of significant size to have been deployed at that scale.
Generated columns are not necessary for indexing in Postgres, you can create an index on any expression based on the record (supported by many versions now).
I was not saying cancellations are not useful, I was saying cancellations are better handled explicitly via cancellation tokens (which compose perfectly, unlike computation based cancellation).
I think the author wants promises to represent computation, whereas they represent predetermined (i.e. single-shot) events. He mentioned C# Tasks, which do mainly represent computation, but in some cases Tasks are also used as events and this gets confusing as hell. I've worked with C# Tasks and hope that MS once cleans this up and builds the stuff on promises instead. Note that the C# language construct uses the awaitable pattern (GetAwaiter method) instead of tasks - awaitables are actually pretty similar to promises.
1. Eager, not lazy - I think it was a mistake for the promise constructor to take a function, and in that way lead the users to believe the promise represents a computation. Creating a pair of promise and future (the latter as the producer side, like in C++) would be much cleaner. I disagree that lazy would be more general, you can simulate lazyness with functions, but you couldn't eliminate the performance cost of creating the unnecessary closure with a lazy solution. Regarding getUserAge - the common case for that function would be to take the user ID as the parameter (and hence would be lazy by construction), the parameterless version is a special case.
2. No cancellation - cancellation is much better represented with cancellation tokens (even C# Tasks cancel with cancellation tokens, so does fun-task mentioned at the end, though in non-composable way) - you cannot build a generic solution that can cancel the right computations. With cancellation tokens it's clear what cancels what.
3. and 4. (as well as being allowed pass non-promises to places where only promises make sense, like Promise.all and await) are unfortunate accidents that make typed environments (e.g. TypeScript) harder to work with but are not that important as 1 and 2.
While I kind of agree with the rule of 3, in the example given, I would just rename BaseScraper to ScraperWithFormLogin when encountering the 3rd instance and not derive the 3rd from anything (or create an abstract BaseScraper) - there's still a high likelyhood there will be another scarper with form login.
Although I very much like C# where generics are not elided, I think most of the value comes from the productivity from static analysis, and therefore Java generics cature most of the value. Perf improvement opportunities are great though.
Except the 99% (though in my experience more like 80% of the cases where generics would be considered in other languages) of the time you are refraining yourseld from using interface{} and perhaps choosing another bad solution (lesser of the evils)
Today I wouldn't recommnend Skype built in any language except Rust. But the Skype founders Ahti Heinla, Jaan Tallinn and Priit Kasesalu found exactly the right balance of C and C++ for the time.
I also wrote a few lines of code in that dialect of C++ (no exceptions). And it didn't feel much different from modern C++ (exception are really fatal errors)
And regarding to embedded, the same codebase was embedded in literally all the ubiquitous TVs of the time, even DECT phones. I bet there are only a few (if any) application codebases of significant size to have been deployed at that scale.