> You can make mistakes in any language, and they will bite you in the backside any way.
This is a false equivalency.. It's akin to saying "you can hit your thumb putting in a nail with any tool, so you might as well use a rock not a hammer since they're both bad".
Yes, you can make mistakes in any language, but that's not a reason to ignore modern tooling and advances and continue.
Other languages allow us to build abstractions and solve mistakes in ways which are just impossible with C... and without those abstractions, it's just needlessly difficult to keep all the state in your head and write correct code.
An easy example of this is locking and ownership.
In C, mutexes are managed manually and what they hold is by convention. It's easy to write races or accidentally deadlock (again as evidenced by such a bug in the kernel existing every few weeks).
In languages with RAII, python's "with", etc, you can't forget to unlock the lock. It's one less thing to think about.
In languages like rust, it's possible to model in the type system that a given resource can only be accessed while a mutex is locked. Again, one less way to make a mistake.
C has no ability to provide or build abstractions that are this robust.
Using C is, more often than not, like using a rock to hammer in a nail.
> Just because some people prefer to live in padded rooms
With C, people are living in a room where the floor is lava and nails coat most surfaces.
I'll take my room that's carpeted, and if I need to pull a stunt and rip up the carpet, sure, I can do that, but at least I can walk normally most of the time.
I've been a professional C++ programmer for almost two decades (and a C++ amateur for almost a decade before that). I've written large amounts of fairly advanced C++ using the latest standards.
My current job however, is all plain C.
One of the interesting (and, for a C++ fan like me, disturbing) things I've found is that the cognitive load is much lower when writing plain well-structured C.
Sure, you need to remember to release that lock and free that memory but this you can do in a very structured way. What you win over C++ is that you don't need to view each line of code with suspicion ("What happens if this line throws an exception?", "I wonder what this line will cost in terms of performance?", "Could this operation cause a cascading destruction of objects I'm going to access further down?").
I love RAII, yet I've debugged enough crashes where "seemingly innocuous operation destructs some local object that has an owning reference to an object that shouldn't be destructed just yet and BAM!", that I'm beginning to doubt its usefulness outside of an exception-generating language (in C++ it's essential for proper exception-handling).
Even from a C amateur point of view I feel the same way in my learning of the language. I can’t speak to multithreading or very large applications yet— but the view from the ground looking up is that C is relatively straightforward. The small size of the language is something of a relief.
It's not very surprising for me, because C is a simpler language and it's easy to paint yourself into a corner with C++.
The critical question is: what does the error rate look like for code of similar complexity? It's very possible that C programmers will try to keep things simple, because the language doesn't support them and they have to be extra careful. The flip-side is that they probably can't develop projects as complex as C++ would enable them to.
Yeah, most projects don't consist of a single function locking and unlocking a mutex. :) Try doing the same in five 200 LOC functions with multiple returns when three different threads are sharing the data, for 10 years, with a yearly personnel turnover of 20%.
Something really unusually stupid like returning from the function (assuming do_something() is a standin for arbitrary code, not specifically a function call)?
This is not even remotely the worst thing about mutexes though, so it wouldn't be why I would suggest avoiding them.
Honestly, to help avoid mistakes, I would keep it as a function call. Sure, it adds to the stack depth, but it also ensures a separate return doesn't cause the lock to be lost.
There's also the goto pattern, but anytime you separate a lock from an unlock by more than a screen's worth of text, they're forgotten.
And inline functions don't even add stack depth. It's still something that happens manually though. Every item that needs to be done manually and doesn't cause obvious failures when not done adds to development costs.
I'm glad you mentioned Python. Python, with its developers who accept raw pickle objects from the wild and are surprised when arbitrary code can be executed. Ruby's (and Python's) YAML libraries which execute arbitrary code. Javascript (and Ruby, and Python) developers pulling in untrusted and/or poorly tested libraries just to save a few lines of code. Rust with its `unsafe` blocks.
Seems like that padded floor has some rusted nails hiding right behind the pretty fabric.
RAII is not something limited to Rust, or C++, or any other language. The abstraction underpinning RAII can be done and has been done in C; you can see it done repeatedly in the code for collectd.
Its up to the developers to make their programs safe and reliable. No language to date will do that for them.
> Its up to the developers to make their programs safe and reliable. No language to date will do that for them.
But languages do make a huge contribution. For example, Rust, Ada and Modula-3 are all much safer by defaults alone compared to C. Most Rust code sits outside unsafe blocks, so the existence of this feature does not prove there is no point to Rust.
I didn't say anything along those lines. I said that it's up to developers to make their programs safe.
Defaults matter, no doubt. But they are not a silver bullet; greater base safety can even cause people to become lax when thinking about safety, resulting in even bigger problems. Why do Python developers accept and parse untrusted pickle objects? Because Python is safe, and they don't have to think about what's going on under the hood.
It's indirectly related to computer programming, but a study was done in Europe which showed that crashes in AWD vechicles were, on average, much more severe than 2WD vehicles. Why? Because of the added stability of AWD, people drove faster in adverse conditions.
This is a false equivalency.. It's akin to saying "you can hit your thumb putting in a nail with any tool, so you might as well use a rock not a hammer since they're both bad".
Yes, you can make mistakes in any language, but that's not a reason to ignore modern tooling and advances and continue.
Other languages allow us to build abstractions and solve mistakes in ways which are just impossible with C... and without those abstractions, it's just needlessly difficult to keep all the state in your head and write correct code.
An easy example of this is locking and ownership. In C, mutexes are managed manually and what they hold is by convention. It's easy to write races or accidentally deadlock (again as evidenced by such a bug in the kernel existing every few weeks).
In languages with RAII, python's "with", etc, you can't forget to unlock the lock. It's one less thing to think about.
In languages like rust, it's possible to model in the type system that a given resource can only be accessed while a mutex is locked. Again, one less way to make a mistake.
C has no ability to provide or build abstractions that are this robust.
Using C is, more often than not, like using a rock to hammer in a nail.
> Just because some people prefer to live in padded rooms
With C, people are living in a room where the floor is lava and nails coat most surfaces.
I'll take my room that's carpeted, and if I need to pull a stunt and rip up the carpet, sure, I can do that, but at least I can walk normally most of the time.