5 ms·
C seems ok no?
by skohan 5y ago
C seems ok no?
- eropple 5y agoYMMV, but to me, C is a great example of a language that absolutely could stand for a few more features. I would almost never write C++ (in the context of low level and performance-relevant code; I write a lot of things for a lot of stuff) if the type system was a touch more rigorous (why can't I specify, and have the compiler yell at me if I don't properly handle, "this pointer may never be null"? TypeScript can do this kind of type narrowing in its sleep!) and if error handling/lifecycle cleanup wasn't hazardous (I'm not even saying exceptions and try-catch, just make it easier to guarantee that a cleanup clause gets called when leaving scope, like Ruby's def-ensure-end). As it is, whenever I finally hit the breaking point with C++ (which I write mostly from inertia because I know it pretty well) it's probably Rust for me.
- skohan 5y agoThat's exactly why Zig is such an interesting language to me. The premise of trying to write a modern C replacement - essentially what C would be if it were designed with the learnings of the past 40 years in mind - is super exciting. I am a fan of Rust, but I am not 100% sold on it. The safety features and ADT's are nice, but I find it quite clunky in practice, and it is just such a huge language full of so many features. It almost feels more like a test language to try the concept of static memory management than a properly designed language in some ways. I feel it's missing the quality from C/C++ that they are a very thin abstraction over assembly.
- eropple 5y agoI haven't looked at Zig much because I mostly noodle with lower-level languages with an eye towards game prototypes and the like, so I don't know much about it. Have anything you'd recommend reading about the language?
- cturtle 5y agoI like Zig because it feels like a refinement of C with all the knowledge of the years since C was created. Some of my favorite features are no global allocator, well-defined pointers (with optionals required for nullability), generics and partial evaluation at compile-time, and builtin features/functions for all sorts of operations that are only extensions in C/C++ like SIMD and packed structs. Read [0] for a comparison among Zig, D, Rust, and C++, and read [1] for a deeper look at the language's goals. I personally really love Zig's type system [2], with a system for generics that is very simple and consistent. [0]: https://ziglang.org/learn/why_zig_rust_d_cpp/ https://ziglang.org/learn/why_zig_rust_d_cpp/ [1]: https://ziglang.org/learn/overview/ https://ziglang.org/learn/overview/ [2]: https://nathancraddock.com/blog/consistency-in-zigs-type-system/ https://nathancraddock.com/blog/consistency-in-zigs-type-sys...
- eropple 5y agoI'm going to give those a read. Thanks!
- Aloha 5y agoI've always understood that C was designed to fit a hardware budget. We knew about many of these features then, when C was created - but it wasn't until the 2000's really where computing horsepower caught up to be able to use them in a universal way.
- skohan 5y agoHmm I've always thought of C in terms of "portable assembly". Not so much that features were omitted because they weren't performant enough, but because they strayed too far away from machine-primitive operations.
- eropple 5y agoC itself is pretty far from the machine, too, except by accident.
- nicoburns 5y agoSome of them would have been great even on 70s hardware. Proper array, slice and string types come to mind.
- nindalf 5y ago> a very thin abstraction over assembly. I think this statement implies that it’s clear and obvious what assembly will be generated from a snippet of C/C++ code. But few people can understand everything that optimising compilers and modern processors do to normal looking code. An example of this lack of knowledge is seeing people disagree on if a snippet contains UB or not. If C is so simple, why do people struggle to write it?
- skohan 5y ago> But few people can understand everything that optimising compilers and modern processors do to normal looking code. Well when I'm talking about an abstraction over assembly I'm not talking about optimizing compilers. That's another topic entirely. What I mean is, if you look at a block of C code, it's very easy to understand what the machine is doing. > If C is so simple, why do people struggle to write it? Do they? I think people struggle to write correct, bug-free code in C, but that's because it doesn't save you from yourself, and it's happy to let you do whatever the hardware will do. That's a much larger programmable space than the set of all safe correct programs. But I don't think people in general have difficulty looking at a snippet of C code and understanding it.
- nindalf 5y ago> What I mean is, if you look at a block of C code, it's very easy to understand what the machine is doing. So they simultaneously understand what the machine is doing but don’t know what assembly will be generated? Both can’t be true. If everyone understood what the machine was doing, everyone would be able to look at a snippet and agree - “that’s UB, let’s not do that”. But they can’t agree. Because few people understand what the compiler and the processor will do. The “thin layer of assembly” was true for the first generation of C compilers. But it hasn’t been true for a long time. It’s a complete black box now. Anyone who thinks that it’s straightforward isn’t being upfront with themselves.
- skohan 5y ago> So they simultaneously understand what the machine is doing but don’t know what assembly will be generated? Both can’t be true. I mean I can understand a reasonable mapping to what the un-optimized assembly would be. Compiler optimization is very complex, and is going to obscure the results in every language. > If everyone understood what the machine was doing, everyone would be able to look at a snippet and agree - “that’s UB, let’s not do that”. But they can’t agree. Because few people understand what the compiler and the processor will do. What? I think everyone can agree that UB is much harder to detect in assembly than in higher level languages than assembly, and assembly gives the most clear view of what the machine is doing. It's a very complex topic to create a system which detects and disallows UB automatically in the compiler - this requires a lot more complexity than a simple mapping of high level instructions to machine instructions. > The “thin layer of assembly” was true for the first generation of C compilers. But it hasn’t been true for a long time. It’s a complete black box now. Anyone who thinks that it’s straightforward isn’t being upfront with themselves. I don't know, seems pretty straightforward to me: https://godbolt.org https://godbolt.org
- pcwalton 5y agoC and C++ are not a very thin abstraction over assembly language. The C virtual machine is very far from the actual hardware. And Rust is the same distance from the hardware as C and C++ are. Rust's core operations are, by and large, the same simple mapping to LLVM instructions. I don't find the idea of a new non-memory-safe C replacement in 2022 very exciting. We should be moving away as an industry from non-memory-safe languages, for the obvious security and productivity reasons.
- skohan 5y agoI don't see how you could argue that C is comparable in terms of level of abstraction to Rust and C++. For instance with Rust memory management is totally abstracted away from you as the programmer, which is a core part of what a computer is doing. And if you index into an array in C, that's basically like saying `root memory location + stride * index`. In Rust it's calling a trait function which could be doing arbitrary work. Rust and C++ are on similar levels of abstraction, but C is much, much simpler.
- pcwalton 5y agoHow is Rust memory management totally abstracted away from you? You have to opt in to every heap allocation, just as you have to call malloc() in C. And it's certainly true that Rust has overloading and C doesn't, but that wasn't what I was getting at. The point is that C is defined in terms of the C virtual machine, not the underlying hardware. The C virtual machine is quite far from the actual CPU instructions.
- pjmlp 5y agoYou mean the learnings of Modula-2 in 1978, but with a C like syntax?
- david2ndaccount 5y agoClang has a nullability extension and associated nullability sanitizer: https://clang.llvm.org/docs/AttributeReference.html#nullability-attributes https://clang.llvm.org/docs/AttributeReference.html#nullabil...
- eropple 5y agoYep! And it's great where you've got it, but the world is not Clang. :(
- restes 5y ago>why can't I specify, and have the compiler yell at me if I don't properly handle, "this pointer may never be null" You can do so easily. A reference is a pointer that is never null.
- eropple 5y agoC++ isn't C.
- restes 5y agoThe GP was referring to C++ >I would almost never write C++ … Edit: nevermind, I missed the point! GP is saying he wouldn’t write C++ if C supported these features.
- stormbrew 5y ago> A reference is a pointer that is never null. This isn't even theoretically true: void blah(int &x) { x++; } int main() { int *x = NULL; blah(*x); } You can definitely write a smart pointer that more or less provides some kind of guarantee about this (with a combo of runtime checks and typefoo) but references only provide a guarantee that they are not statically initializable to null, which is very different.
- restes 5y agoCompilers are free to assume x is non-null at the time it’s dereferenced, so isn’t it true by definition? Do you have an example that doesn’t rely on undefined behavior?
- stormbrew 5y ago"Compilers are free to assume" is a fine thing for like, a loop, but the compiler isn't free to assume you didn't mean to dereference the reference in the code snippet I posted, it's just free to not check before it does. So it will crash, whether that's undefined behaviour or not. The thing at issue here is that other languages have reference types that are more strictly statically guaranteed to be non-null. My point is that references are not a substitute for those, because holding them wrong is not only easy, it's extremely likely to happen in code of any reasonable complixity that mixes pointers and references (ie. almost all production C++ code).
- Isognoviastoma 5y agoC begins to increase rate of adding breaking changes. C23 is about to - add keywords that was valid identifiers before - remove K&R parameter syntax - change semantics of the most popular function argument list declaration - forbid representations other than 2's complement https://news.ycombinator.com/item?id=30395016 https://news.ycombinator.com/item?id=30395016
- kevin_thibedeau 5y agoWhat new keywords? Everything new goes into the reserved namespace with macros to look like the C++ versions.
- duped 5y agoThe over adherence to bloat in the name of backwards compatibility holds the language back - these are incredibly conservative changes that reflect practices which have already been used for decades!