9 ms·
Tangentially, I'd love to see some list of "what does this language make easy" (C: raw memory manipulation!) and "makes hard" (C: memory-safe code)... Does one
by AceJohnny2 9y ago
Tangentially, I'd love to see some list of "what does this language make easy" (C: raw memory manipulation!) and "makes hard" (C: memory-safe code)...
Does one exist for Rust?
- leetcrew 9y agotbh I don't know enough about rust or the whole field of software development to give an authoritative answer, but if you don't know much about rust, this might help you. in general, rust is great for pretty much anything c is great for. you can do raw memory manipulation in unsafe blocks if you want, but you write memory safe code by default. at present, rust is definitely slower than c, but there's no inherent reason that it has to be so; mainly it's just the consequence of being a new and immature language. one neat thing you can do with rust is build safe interfaces to the c libraries that you know and love for a relatively small performance penalty. I am writing a toy graphics application in rust, and it is so much nicer than bare OpenGL, although there are some serious pain points with library maturity. it can also be a decent substitute for problems you might solve in C# / Java / other statically-typed languages, although it is a bit more strict and explicit than those. the main things I can think of that rust makes hard are applications where you really don't want static typing (web dev, scripting, etc.) or you have a need to use a lot of specific libraries that you don't feel like writing interfaces for.
- Const-me 9y ago> rust is great for pretty much anything c is great for No it’s not. > you can do raw memory manipulation in unsafe blocks if you want You can but Rust is not great at it. At least not in comparison with C or C++. In C, people have been writing these unsafe memory manipulations for half a century, accumulating knowledge, working on runtime & libraries, and building tools like verifiers, debuggers, profilers. C++ has even more of these, adding some safety features to language and standard library while still being C compatible.
- leetcrew 9y agomost of this seems to be an issue of maturity for the language itself and the surrounding ecosystem, which I did touch on a little bit. I probably should have made it a more explicit caveat. aside from ubiquity and maturity, I'm curious what features c has that rust lacks for raw memory manipulation. I have yet to work my way through all of the rustonomicon and I am far from an expert c programmer, so I would appreciate the opportunity to fill in some knowledge gaps.
- Const-me 9y agoI agree that for C it’s mostly the ecosystem i.e. external tools & libraries. There’re just a few features in the language and runtime, such as debug heap and the preprocessor. But C++ has a lot to offer besides tooling. Modern-style C++ (template containers, smart pointers) solve the majority of safety issues solved by safe Rust. But C++ doesn’t hide these raw pointers behind safe abstractions, and that higher level safer stuff is optional. For specific features helping with raw memory manipulation see e.g. routines from <algorithm> header, http://en.cppreference.com/w/cpp/algorithm http://en.cppreference.com/w/cpp/algorithm They are part of C++ standard library, and yet they support dangerous C arrays, because raw C pointers double as C++ iterators.
- steveklabnik 9y agoI’d characterize the situation differently; Rust handles a lot of things that Modern C++, and not even the Core Guidelines, try to handle. Iteration invalidation is huge. Concurrency and parallelism issues are huge. I very much welcome these things, as I’m about safe software, not “only Rust”, but I don’t think the “most” claim holds water.
- Const-me 9y agoIt’s all about tradeoffs. If you prioritize performance over safety, there’s no way around these problems. To implement efficient algorithms processing trees, lists or graphs, you have to fallback to unsafe code & potentially invalid raw pointers. Unsafe Rust is as dangerous as C++, but for C++, standard library, runtime and tools provide huge help implementing and debugging such things. If you prioritize safety over performance, of course Rust is way ahead of C++. But Java and C# are much easier to use and deliver safety comparable to Rust. Also in these languages, trees & graphs might be even faster than in safe Rust.
- zenhack 9y agoI will contest the idea that you don't want static typing for web dev. Curious, what statically typed languages do you have experience with? I ask because you only mention C# and Java, and I often find people who form their ideas about types from those languages think they have to be much more cumbersome than they really do.
- leetcrew 9y ago> what statically typed languages do you have experience with? c, c++, java, rust, c#, so the assumption you're making is probably correct.
- zenhack 9y agoIf you're at all interested in taking the red pill: elm and reason/ocaml are some things worth checking out. There is so much more out there than the C family tree.
- smitherfield 9y ago> "what does this language make easy" (C: raw memory manipulation!) Depending on what you mean by "raw memory manipulation" that can actually be surprisingly difficult with C, without running into undefined behavior, at least technically-speaking. e.g. type-punning through unions is defined by all implementations I can think of, but technically UB according to the standard. That said, if you know the UB rules, C/C++ are still the "nicest" mainstream languages to use for that sort of super-low-level manipulation of raw object representations. The non-UB type-punning methods in C/C++ (`memcpy(3)`, casting addresses to pointer-to-`char`), finicky as they are, are still more ergonomic and, ironically, safer than Rust's poorly-designed `mem::transmute()` API. Language-lawyering is quite the rabbit hole, BTW; for example, it was discovered a few years ago that the wording of the formal C++ memory model defined in the C++11 and later standards means all non-trivial C programs (technically-speaking, not according to any existing or sane implementation) invoke undefined behavior in C++. We'll be lucky if the bikeshedding over the fix for this gets resolved in time to make C++20. #include <stdlib.h> void *safe_ptr(void *p) { if (!p) exit(1); return p; } #define INIT(TYPE) safe_ptr(malloc(sizeof(TYPE))) int *get_intbuffer(void) { enum {N=3}; int *const intbuffer = (int*)INIT(int[N]); int i = N; /* Technically UB in C++; lifetime starts * w/ declaration or initializing w/ new * or placement-new, so reads/writes thru * the result of malloc w/o initializing * the objects w/ placement-new are UB */ while (i--) intbuffer[i] = i; return intbuffer; }
- dbaupp 9y ago> are still more ergonomic and, ironically, safer than Rust's poorly-designed `mem::transmute()` API. Eh, I disagree. I find: let x: f32 = ...; let y: i32 = mem::transmute(x); is nicer than float x = ...; int y; memcpy(&y, &x, sizeof x); And, in terms of safety, transmute manages the sizes of everything and makes sure they match. There's no risk of passing the wrong size, or having types with mismatched sizes (resulting in either "slicing", or buffer overflows). The only way I can see transmute being more dangerous than the equivalent is that one can allow the types to be inferred, which can result in badness if the inferred type isn't what the programmer is expecting. This is especially dangerous when type involves a lifetime. (I suppose one could argue that it also makes this dangerous operation easier to do, since there's an easy-to-find function for it. But... this goes both ways, since it also stops people being tempted into using undefined pointer casting like ^(float ^)(x) (using ^ for * since HN likes italics too much).) > Language-lawyering is quite the rabbit hole, BTW; for example, it was discovered a few years ago that the wording of the formal C++ memory model defined in the C++11 and later standards means all non-trivial C programs (technically-speaking, not according to any existing or sane implementation) invoke undefined behavior in C++. We'll be lucky if the bikeshedding over the fix for this gets resolved in time to make C++20. I'm curious if you've got a defect report link or similar, because my reading of "6.8 Object Lifetime" in the C++17 draft implies that the lifetime has started for those int objects since the two conditions are both satisfied: - "storage with the proper alignment and size for type T is obtained": the malloc'd pointer is fine. - "if the object has non-vacuous initialization, its initialization is complete": ints have vacuous initialization. But, I'm probably wrong, and would appreciate being corrected.