Please don’t start a C flame war either HN. I know I’m nerd sniping you all on this one
Please don’t start a C flame war either HN. I know I’m nerd sniping you all on this one
C _looks_ simple, deceivingly so. As soon as you need to deal with a large project in a corporate environment on a code base aged in double digit years you don't think it's simple anymore. C is incredibly complex, unmanageably so.
But, I’m not arguing with you. I honestly think that any corporate codebase after double digit years (and seven figure LoC) turns into a completely unmanageable mess. If it isn’t, it’s because of the team culture and pure rigor. Not the language
I don't limit my statement to just C. The topic was C however so I mentioned C.
Your comment reads like a red herring though. You're not actually trying to argue that C makes thing easier or hard. Your red herring only means that hard problems affecting all languages aren't magically turned into non-issues in C. You can still write a C program that uses threading and is as safe as any other language and end up being a far simpler project, but that means nothing because the subject is still hard. And what would that actually say about C, let alone refute?
I’ve worked in a lot of massive and unmaintainable codebases, and I’ve always had the most fun untangling C ones. I don’t know exactly why, but I suspect it’s because at their core they are always plain ol’ simple C.
Writing C is simple.
Writing multithreaded programs is difficult and C doesn't help you with it.
Let's not argue about religions online. The mullahs will arrest us for improper use of void.
I've done this before, never felt like C wasn't simple.
I think your main argument here is that large C code bases can easily become unwieldy, and I agree with you on that. However, simple multithreading in C is simple. It's not a terribly difficult problem to solve.
Sharpened rock is a simple tool. Versatile too, but try using it to make a sculpture and it's going to be hard, very hard. Especially if you never used it extensively.
C is a simple language. No doubt about it. But doing multi-threading and memory safety in C is like trying to build a 100m tall structure using nothing but a sharpened rock. Possible but, why would you.
Java is a complex language. Lots of complexity. Classes, annotations, async, System.out and so on. But multi-threaded and memory safe (memory leaks allowed ofc) programs is as simple as just not using Java's array of unsafe tooling.
> But multi-threaded and memory safe (memory leaks allowed ofc) programs is as simple as just not using Java's array of unsafe tooling.
as _easy_ as just not...
"Complex" is the opposite of "simple". "Easy" is the opposite of "hard".
I could port most of the multiprocessing based python scripts I have lying around to C without a problem. Multithreading can be easy when you have a few rules in place what threads can read/modify data at a specific point in time.
In a corporate environment, just use Java or C# or whatever. It's a corporate environment, probably not that interesting. C is not necessary.
Even modern drivers for Apple, Google and Microsoft platforms are written in C++.
Mind expanding on that?
In my experience it's only the language lawyers who actually know what to look out for, and there are damned few of them.
Which is stupid since undefined and unspecified behaviors are hugely important to how C and C++ are used in the field.
Is it really that fundamental if you can setup your project to throw warnings/errors, and even use static code analysis tools to flag those?
I'd argue that it's far worse to work on a project that's not setup to detect those errors than to expect that sort of issue to be handled at the recruiting level.
Why are they though? Should they be?
(But, I also totally concede that a language is inseparable from its std lib in reality)
It is a feature introduced by compiler writers who prize esoteric optimisations more than simplicity.
And it is not forbidden by the standard, though discouraged.
How so? It is behavior left undefined in the C standard.
> It is a feature introduced by compiler writers who prize esoteric optimisations more than simplicity.
It's not the compiler writers who left the behaviour undefined, but the standard writers. If it was so clear what should be done (so all compiler writers should do it in one way) then why did they not define it?
> And it is not forbidden by the standard, though discouraged.
What do you mean it's not forbidden in the standard, it's undefined in the standard hence the name. Because of this you really should not rely on it, because the behavior could change.
Use-after-free or double-free is undefined behavior.
Therefore a C implementation that provides malloc(3) should provide an implementation of free(3) that is a no-op and provide a garbage collector that actually frees the memory.
It's not an argument, it's an observation and statement of fact.
> Use-after-free or double-free is undefined behavior.
Yes.
> Therefore
Why therefore?
> a C implementation that provides malloc(3) should provide an implementation of free(3) that is a no-op and provide a garbage collector that actually frees the memory.
If you think so. It certainly doesn't follow from what I wrote. My point is that if you use a pointer after you freed the memory, you get whatever is in memory that the pointer points at on the machine the code is running on.
That is not a "weird and bizarre" implication, it is a plain and straightforward implication given how C is implemented on real machines. It is (obviously, I hope!) outside of the scope of the C standard to say what will be at that memory location at that point, and therefore it is UB.
And it being UB, "what you get" may also, for example, be a segfault because the library/OS have decided to unmap that memory. And again, that is also not "weird and bizarre", but perfectly straightforward.
¯\_(ツ)_/¯
It's an error even if it's undetectable by the compiler. I understand that nomenclature from few decades ago makes a distinction but nowadays we just call such thing an error.
C has near universal portability. It's everywhere. That's the most important property.
That’s what I mean by simple. And that’s the reason why it also has universal portability. Cause it’s simple
I first learned C when I was 11 years old; admittedly I learned BASIC and Z80 assembly before then, and I'm an outlier.