[HN Gopher] The C++ Killers (Not You, Rust)
       ___________________________________________________________________
        
       The C++ Killers (Not You, Rust)
        
       Author : todsacerdoti
       Score  : 67 points
       Date   : 2024-03-20 18:44 UTC (4 hours ago)
        
 (HTM) web link (wordsandbuttons.online)
 (TXT) w3m dump (wordsandbuttons.online)
        
       | sylware wrote:
       | rv64 assembly is the new C.
        
       | bfrog wrote:
       | C++ itself seems to be working pretty hard year after year on
       | this task of killing C++ with endless half baked features that
       | fail to address real problems
        
         | zabzonk wrote:
         | they do address real problems - specifically those of people
         | trying to write very efficient libraries. if you are not in
         | that group, simply don't use those features.
        
           | UncleMeat wrote:
           | And yet they can't update the standard library types to not
           | be slow as hell because of ABI concerns.
           | 
           | If C++ was really all about speed then we'd have destructive
           | move letting you pass unique_ptr in a register without
           | compiler trickery. The fundamental number one constraint on
           | new C++ behaviors is ABI compatibility. The rest is
           | secondary.
        
             | zabzonk wrote:
             | the c++ standard does not specify an ABI.
        
               | UncleMeat wrote:
               | The c++ standard absolutely cares deeply about abi
               | compatibility. The committee can't even update intmax_t
               | because it is an abi break. "Code compiled today and
               | linked against code compiled years and years ago must
               | behave correctly" is an absolutely premier design
               | constraint when it comes to papers and it has prevented
               | oodles of low hanging performance opportunities.
        
               | zabzonk wrote:
               | quote from standard where it says that?
        
           | Const-me wrote:
           | Sadly, the C++ standard bodies are actually breaking old code
           | in new versions of the language.
           | 
           | For example, C++/11 introduced UTF8 string literals. Great
           | feature which does what you'd expect - declare a string
           | literal in source code, get a const pointer to null-
           | terminated array of utf-8 bytes.
           | 
           | Then a decade later, in C++/20 they refactored these UTF8
           | literals to evaluate into const pointers to the new
           | incompatible data type, char8_t.
           | 
           | It's so bad that compiler developers had to implement
           | switches to disable the new BS. Unfortunately, these switches
           | are incompatible across compilers, -fno-char8_t in gcc,
           | /Zc:char8_t- in msvc.
        
       | ilovefood wrote:
       | Beautiful and well written article. Unfortunately I made a small
       | mistake in the second quizz :P
        
       | felipellrocha wrote:
       | > The matter is, none of the languages, especially the so-called
       | "C++ killers" give any real advantage over C++ in the modern
       | world.
       | 
       | To you. There are pleeenty of people who want to write performant
       | code in a safe manner.
        
       | pipeline_peak wrote:
       | > None of these questions have a definite answer without context.
       | 
       | This is a pretty annoying thing to do considering someone took
       | the time to read through all this.
       | 
       | Also not original, I've seen posts in here like this 3 times
       | already
        
       | arcticbull wrote:
       | > But why can't I just quit then? What's the matter? The matter
       | is, none of the languages, especially the so-called "C++ killers"
       | give any real advantage over C++ in the modern world. All those
       | new languages are mostly focused on holding a programmer on a
       | leash for their own good.
       | 
       | This, very specifically, is the advantage these languages have
       | over C++.
       | 
       | The benefit isn't the universe of things you can do (they're all
       | Turing complete, you can do anything) - it's what the language
       | stops you from doing. This is the thing the C++ committee never
       | understood or at the very least never appreciated.
        
         | zabzonk wrote:
         | why do you think the designers of those new languages know what
         | is good for you?
        
           | kstrauser wrote:
           | Because they tell me to stop managing memory by hand, as we
           | have mountains of experiment proof that no one[0] is good at
           | it.
           | 
           | [0] I meant what I said.
        
             | zabzonk wrote:
             | um, modern c++ has for at least the past 10 years advised
             | people not to manually manage memory.
        
               | dekken_ wrote:
               | not really, RAII/shared_ptrs is still manual memory
               | management, just less footguns
        
               | zabzonk wrote:
               | well, i would not recommend shared_ptr except under rare
               | circumstances, but i don't see what can be wrong with
               | RAII. in fact, it is the languages thar don't have RAII
               | that have the problems, IMHO.
        
           | andyferris wrote:
           | One thing I love about C++ is it (mostly) stops me making
           | type errors, compared to dynamic languages - "compile and it
           | works". Adding type constraints makes programming safer,
           | easier, and results in better compilation.
           | 
           | You can add other constraints (e.g. temporal constraints) and
           | get similar benefits, on top of the above.
        
           | dale_glass wrote:
           | Because I believe safety critical places like aviation are
           | the ones that actually get things right. You can't pile on
           | every demand on the human in charge and expect improvement.
           | We're just not great at taking every possible detail into
           | account. Doing lots of grunt work all the time reliably is
           | what we have computers for.
           | 
           | In my old age, I find the more permissive a language is, the
           | more painful it is to code in long term. Perl is great for
           | simple things, but C++ was a vast improvement because it
           | catches a lot of nonsense that Perl will compile just fine.
           | 
           | And debugging is so expensive that eventually writing code
           | fast is near worthless. Whatever you gain you more than pay
           | for in debugging afterwards.
           | 
           | C++ unfortunately doesn't go far enough.
        
             | zabzonk wrote:
             | yes - i switched from C to C++ a long, long time ago (late
             | 1980s) because C++ was so much more strongly typed (i still
             | don't understand why other C programmers have stuck with
             | C). i'm less than convinced with the promises of rust (for
             | e.g.), but have only written trivial programs in it.
        
           | steveklabnik wrote:
           | They don't. What they do is create a system where the system
           | protects itself from human error. They don't know better than
           | me: I agree with what they're doing. Automatic enforcement of
           | good things, plus an escape hatch for emergencies, is better
           | than no restrictions ever.
        
           | wk_end wrote:
           | I assume you program in assembly language, then? Can't trust
           | those structured programming types to know best how to manage
           | your instruction pointer after all. "Functions", "loops",
           | "conditionals", all just fancy words for straitjackets.
        
             | vundercind wrote:
             | I'd love a demographic study of folks who are really
             | unhappy about languages like Rust and Go specifically
             | because they believe they're crushing their creative
             | spirit. The "I need MAXIMAL EXPRESSIVENESS at all times!
             | Don't tell me how to do things!" sort
             | 
             | I hesitate to even guess what the findings would look like,
             | but I bet it'd be interesting.
        
             | tmtvl wrote:
             | But when programming in assembly you're still beholden to
             | the CPU designers in regards to out of order execution and
             | branch prediction and all those fancy layers taking runtime
             | control away from you. Better to just print your own
             | silicon.
        
           | keybored wrote:
           | Language implementers _ought to_ know better than me (the
           | user) about programming language semantics, in this case
           | specifically things like memory safety.
        
             | mgaunard wrote:
             | Memory safety is a very small fraction of the problems a
             | computer program can have, and replacing them by an
             | immediate shutdown is hardly a very useful improvement on
             | program quality.
        
               | sophacles wrote:
               | > Memory safety is a very small fraction of the problems
               | a computer program can have
               | 
               | And a large fraction of the problems that lead to
               | security situations. Worse, they are often so subtle that
               | they stay in a codebase for decades.
               | 
               | > and replacing them by an immediate shutdown is hardly a
               | very useful improvement on program quality.
               | 
               | That's a pretty absolutist statement about something
               | that's very context dependent.
        
           | stavros wrote:
           | This is a bit of a misnomer, languages don't generally _stop_
           | you from doing things. They just make really damn sure that
           | you aren 't doing it by accident.
        
           | Brian_K_White wrote:
           | what do you think those new languages prevent you from doing?
        
           | UncleMeat wrote:
           | Is a bounds check on every container access good for me? Not
           | always. Sometimes my code is correct. But security
           | vulnerabilities are observably a huge problem. And you only
           | need one vuln in iMessage or whatever to get a dissident
           | journalist's phone hacked and then get them murdered by the
           | Saudi government. Is "I know what I'm doing, I promise" good
           | enough for you in that case?
           | 
           | I find it interesting because until about three years ago,
           | C++ was always on the other side of this argument. We fight
           | about static type systems. You could shout at the compiler
           | that you know that your code is correct even though the type
           | system doesn't pass. Why does the committee think it knows
           | better than me! Everything is just bits after all!
           | 
           | Now we are on the other side. C++ people saying "bro I
           | totally promise I'll initialize this data member before it is
           | used, stop making me initialize it in my constructor"
        
             | zabzonk wrote:
             | > Now we are on the other side. C++ people saying "bro I
             | totally promise I'll initialize this data member before it
             | is used, stop making me initialize it in my constructor"
             | 
             | C++ has never said this - if a type has a constructor, that
             | constructor will always be used in a data member (or
             | elsewhere).
        
               | UncleMeat wrote:
               | ???
               | 
               | You can absolutely write a type like this.
               | class Foo {          public:           Foo() {}  // never
               | initialized x           int x;          }
               | 
               | And then using it like this                   Foo f;
               | bar(foo.x);  // oops
               | 
               | "But my types are well designed" is the usual response to
               | "why the heck does the language allow you to quietly
               | expose yourself to UB in this way?"
        
               | munificent wrote:
               | zabzonk said "if a type has a constructor", but I don't
               | think the int type does, which is why you get
               | uninitialized memory here.
               | 
               | Any instance of Foo will run Foo's constructor because
               | Foo has one. The problem is that that instance of Foo
               | won't definitely have x initialized, because int doesn't.
        
               | zabzonk wrote:
               | i said "if a type has a constructor". but if you are
               | fiddling around with ints and chars and the like, then
               | you will need to initialise them. i have been writing c++
               | since the mid80s and have never found this to be a
               | problem, or at least no more than it would be to use an
               | uninitialised int variable in C.
        
               | arcticbull wrote:
               | The fact this is even a distinction anyone has to keep in
               | mind is again and example of the problem. People are
               | _awful_ at remembering these weird little details. We
               | shouldn 't make expect people do things they're bad at,
               | all the time, and well. And I'll go a step further and
               | say we shouldn't _let_ them by default. They should have
               | to make it super explicit they want to opt into the weird
               | behavior nobody expects.
               | 
               | You can do this in Rust if you want! You just have to use
               | unsafe { mem::uninitialized() } or even better, the newer
               | unsafe { mem::MaybeUninit::uninit() }
               | 
               | The whole point is that you _probably_ don 't ever want
               | to have an uninitialized variable you can access willy-
               | nilly, and if you do, you should be very explicit.
               | 
               | Even your statement about C (and C++) isn't quite
               | accurate, right, because anything static is guaranteed to
               | be initialized to zero on creation. So while `int x` is a
               | free for all, `static int x` is gonna be zero. Another
               | thing people shouldn't have to think about!
               | 
               | Principle of least surprise.
        
           | munificent wrote:
           | This is such a silly send-up. They don't know what's good for
           | me. They tell me what their language is good for. I decide if
           | what the language is good for is good for me.
        
           | vundercind wrote:
           | How could they know that?
           | 
           | They might know how to design a language such that it tends
           | to produce exceptionally readable codebases, good
           | performance, and improved safety, though. Maybe not all three
           | at once, but some mix of those that's better than existing
           | languages, perhaps.
        
         | scrubs wrote:
         | If Austin Powers was a programmer:
         | 
         | On a leash? What? ... [if only I could work in a] consequence-
         | free environment, I'll be sound as a pound!
        
         | spease wrote:
         | In other words, the "feature" those languages have is reducing
         | the cognitive complexity and more tightly bounding the risk.
         | 
         | Newer languages are adding friction or dropping altogether
         | things that you rarely or never want to do, to more tightly
         | constrain the space of possible actions to the set of desired
         | actions.
        
       | wslh wrote:
       | Great article more about different approaches to building
       | software that languages themselves.
       | 
       | My two cents: it is improbable that C++ will be ever replaced
       | because it is a mastodon as a programming language: super
       | complex, where complex includes complexity as difficulties and
       | also its vastness. This doesn't mean that it will increase its
       | usage since it is common nowadays to use specific programming
       | languages (e.g. Python) for specific purposes and rely on C++ and
       | others for very specific areas. Personally, I really liked SWIG
       | [1] as a wrapper and interface generator. Don't know how much it
       | is used today.
       | 
       | Other experience but similar conclusion than the article.
        
       | pornel wrote:
       | Looks like the author is very focused on maximally optimizing
       | some very compute-heavy signal-processing code, and doesn't care
       | much what is used outside of the compute kernel.
       | 
       | So it may be very true that for their work it's all the same
       | whether they use C++, or Python with numeric libraries, or some
       | niche DSL, or a macroassembler.
       | 
       | But use of C++ is much broader than pure compute, so this
       | perspective does not generalize to C++ or Rust as a whole.
        
       | bun_terminator wrote:
       | > Do you know that in MSVC uint16_t(50000) + uin16_t(50000) ==
       | -1794967296?
       | 
       | Not only is that insane code and both my compiler and static
       | analysis go for my throat, it's also not true. I think the
       | argument is supposed to be about unsigned integer overflow, but
       | the numbers don't add up. The big negative number wraps to 63744.
       | And the sum (100K) wraps to 34464.
        
         | dzaima wrote:
         | It seems the intent was for "*" to be used instead of "+". At
         | which point it's actually undefined behavior even though the
         | operands are unsigned!
        
           | bun_terminator wrote:
           | that makes more sense!
        
       | lookitsnicholas wrote:
       | may be slightly off-topic, but that website favicon is
       | suspiciously reminiscent of the logo that Ableton currently use
       | hahah
        
       | omoikane wrote:
       | > Do you know that in MSVC uint16_t(50000) + uin16_t(50000) ==
       | -1794967296?
       | 
       | There are two typos in this statement, one is "uin16_t" should
       | have been "uint16_t", the other is that the "+" should have been
       | "*". Searching for 1794967296 yields this answer:
       | 
       | https://stackoverflow.com/questions/18161443/type-casting-wh...
        
       | tomcam wrote:
       | > I made a simple Lisp-style interpreter to help game designers
       | automate resource loading, and went on a vacation. When I was
       | back, they were writing the whole game scenes in this interpreter
       | so we had to support it for a while.
       | 
       | I very much want to hear that story
        
       | mgaunard wrote:
       | Of course I know that uint16_t+uint16_t gives an int. If you're
       | gonna be programming in C or C++, you need to know these things.
       | 
       | And yes, I do agree the fact that I know so much minutiae about
       | those languages is part of the reason why I'm reluctant to go for
       | something else I have a more shallow knowledge of. But that level
       | of attention to detail is also what allows me to deliver high-
       | quality code that does exactly what I intend it to do.
        
       | imadj wrote:
       | Related discussion:
       | 
       | The C++ Killers (Not You, Rust) - Feb 2023 (59 comments) :
       | https://news.ycombinator.com/item?id=34792932
       | 
       | It seems author has published the article last year but moved it
       | to his blog now
        
       | npongratz wrote:
       | > Just as Latin never actually died, just like COBOL, Algol 68,
       | and Ada, - C++ is doomed to eternal half-existence between life
       | and death.
       | 
       | I'm almost afraid to ask, but I'd love to know: are there any
       | Algol 68 projects in active use? Anyone have war stories of
       | maintaining them (bug fixes, new features, improvements to
       | interface with more modern systems) in the last couple decades?
        
         | zabzonk wrote:
         | certainly not active, but back in the 1980s i got dumped on a
         | program that used algol, bcpl, fortran and cobol to drive a
         | phototypesetter to do ... something. this took advantage of the
         | fact that the dec10 allowed you to mix & match languages, much
         | like the vax. i suppose i was lucky the idiot that originally
         | wrote it didn't throw lisp into the pot.
         | 
         | anyway, as i was hired as a microcomputer specialist, and as
         | two dec10 systems programmers had ducked it, i simply said "no
         | can do" - a valuable lesson.
         | 
         | this is what i like about HN - recalling things i had
         | completely forgotten!
        
       | mgaunard wrote:
       | The sine polynomial is bad because it's not written in a way that
       | removes redundant multiplications.
       | 
       | Those redundant multiplications cannot be removed without fast
       | math because floating-point operations are not associative.
       | 
       | There are well-known optimal ways to evaluate a polynomial,
       | namely Horner's and Estrin's schemes.
        
       | marmaduke wrote:
       | Numba is great but missing explicit simd, stack allocated arrays,
       | and user defined types, to name a few things. I tried to keep my
       | colleagues in Jax these days.
        
       | xiaodai wrote:
       | Nicely written. I learned a lot
        
       ___________________________________________________________________
       (page generated 2024-03-20 23:01 UTC)