9 ms·
C at the very least teaches the difference between stack and heap memory, a crucial concept obscured by most higher-level languages.
by ashleyn 8y ago
C at the very least teaches the difference between stack and heap memory, a crucial concept obscured by most higher-level languages.
- flyinglizard 8y agoOr passing by value vs passing a pointer, or the importance of memory management... Modern languages solve problems created developing in legacy languages (primarily C). The issue is that knowing a solution without knowing the prior problem which the solution addresses, doesn't really lend itself to clarity.
- Sir_Cmpwn 8y agoThey don't solve problems created by C, they just solve problems C doesn't. The problems still exist, and sometimes the high-level compiler even picks the wrong solution. Learning C helps you understand when and why this has happened.
- flyinglizard 8y agoArguably those problems did not exist before the C-era as software wasn't large or complicated enough. C++ directly attempts to improve over C by providing new mechanisms to solve problems encountered by C developers every day. Point is that out of context, a lot of the things modern languages provide seem superfluous. Why have objects? Why have templates, closures, or lambdas? For a novice programmer, these are many answers for questions yet to be asked. When you come from a heavy C background and you encounter something like templates, you know EXACTLY what this is for and wish you had it years ago. I'm as hardcore as they get C programmer and I'm having a ball with C# for this very reason.
- Sir_Cmpwn 8y agoWhen I see templates, I run in the opposite direction at a dead sprint. C++ has added very little of value to the language and templates are one of their worst offerings. Metaprogramming is an antipattern in C.
- sevensor 8y ago> Metaprogramming is an antipattern in C. Yet we often see passionate arguments in its favor, as for instance from Sústrik (http://250bpm.com/blog:56 http://250bpm.com/blog:56) and Tatham (https://www.chiark.greenend.org.uk/~sgtatham/mp/ https://www.chiark.greenend.org.uk/~sgtatham/mp/) and a person on the internet who recommends replacing LAPACK with preprocessor macros (http://wordsandbuttons.online/outperforming_lapack_with_c_metaprogramming.html http://wordsandbuttons.online/outperforming_lapack_with_c_me...). Would you care to comment on its enduring popularity?
- Sir_Cmpwn 8y agoYou can write bad code in any language, C is no exception. We also see people persistently arguing in favor of simpler and less magical C. If you want reliable, maintainable code in any language, do not use magic. Metaprogramming is cool, no doubt about it, but it's unnecessary and creates bad code.
- lmm 8y ago"Exploding" undefined behaviour is a problem created by C. Other languages don't have it, not even assembly languages.
- steveklabnik 8y agoThere are many languages which have undefined behavior. C does have a lot of it, and it can be anywhere. In many languages, you can cause undefined behavior through its FFI. Some languages, like Rust, have UB, but only in well-defined places (a module containing unsafe code, in its case).
- lmm 8y agoIf a language lets you cause undefined behaviour via FFI into C, I think it's fair to say that that remains a problem created by C. I do take your point about Rust, but I'd see that as deriving from LLVM's undefined behaviour which in turn descends from C; I'm not aware of any pre-C languages having C-style exploding undefined behaviour or of any subsequent languages inventing it independently.
- steveklabnik 8y ago> I think it's fair to say that that remains a problem created by C. That is fair, however, I don't think it's inherently due to C. Yes, most languages use the C ABI for FFI, but that doesn't mean they have to; it's a more general problem when combining two systems, they cannot track statically the guarantees of the other system. With Rust, it has nothing to do with LLVM; it has to do with the fact that we cannot track things, that's why it's unsafe! Even if an implementation of the language does not use LLVM, we will still have UB.
- lmm 8y ago> With Rust, it has nothing to do with LLVM; it has to do with the fact that we cannot track things, that's why it's unsafe! Even if an implementation of the language does not use LLVM, we will still have UB. I can see that any implementation of unsafe Rust would always have assembly-like unsafeness (e.g. reading an arbitrary memory address might result in an arbitrary value, or segfault). But I don't see why you would need C-style "arbitrary lines before and after the line that will not execute, reads from unrelated memory addresses will return arbitrary values" UB?
- sephoric 8y agoMemory management in C is very different than memory management in JavaScript, which throws exceptions when you try to access invalid memory, but will gladly let you create memory leaks inside event callbacks or other loops and keep chugging along gladly until it can't anymore. Writing a safe, efficient, high performing JavaScript app is very different than writing the same thing in C, and although I know both deeply well, I don't think learning C has helped me write better JS.
- oleganza 8y agoAfter recently (1 year) learning Rust I noticed that Rust teaches about low-level CS concepts of passing by value vs passing by pointer a lot better than C. Because you not just have references and values, but also have to think about richer semantics of what you are trying to do: sharing, mutability, and move semantics. So you learn not only that a few low level concepts exist, but you also learn how to use them correctly.
- jreck 8y agoYou can also learn that difference in something like C#. You don't need C for that. And C pretends there's a distinction between the stack & heap that doesn't actually exist. There is no significant difference there.
- Sir_Cmpwn 8y agoYou're joking. There's a very serious distinction between the stack and the heap - perhaps they live in the same memory but they are used very differently and if you mix them up your things will break.
- rrauenza 8y ago...like returning a pointer to the stack: char *dupstr(const char *src) { char new[1024]; strlcpy(new, src, 1024); return new; }
- TheOtherHobbes 8y agoThere is no hardware distinction between stack memory and heap memory. In fact C teaches a model of a semi-standard virtual architecture - loosely based on the DEC PDP7 and/or PDP11 - which is long gone from real hardware. Real hardware today has multiple abstraction layers under the assembly code, and all but the top layer is inaccessible. So there's no single definitive model of "How computers work." They work at whatever level of abstraction you need them to work. You should definitely be familiar with a good selection of levels - and unless you're doing chip design, they're all equally real.
- t0mbstone 8y agoJust playing devil's advocate here... why is this such a "crucial" concept, for someone who is using a higher level language (like Python or Ruby)? If 99% of what that person does is gluing together APIs and software modules, and they can see their memory usages are well within range, why does it matter?
- pq0ak2nnd 8y agotrue. it's like interior decorator vs. interior designer if you're just going to move couches around and put down throw pillows, who cares about a solid foundation of design fundamentals and architectural psychology.
- mturmon 8y agoYep. In truth, one can almost never win the argument of, "...but do I really need to know this?" But people should be aware that knowing fundamental things provides insight and advantages.
- greenshackle2 8y agoFor sure, but there are diminishing returns. My rule of thumb is that understanding two levels of abstraction below whatever you're doing is usually worth it.
- gowld 8y agoIt's also like fluid dynamicist vs quantum physicists. If you're just going to move oil around and put down differential equations, who cares about a solid foundation of quantum gravity and chromodynamics.
- danso 8y agoI can’t make a thorough argument, but u/flyinglizard (in a comment adjacent to mine) mentioned what I was thinking: Ruby/Python almost entirely abstracts the concept of pointers, references, and memory. For beginners and intermediates, it’s not a big deal until you get mutable data structures like lists and dicts. When I learned CS, we were taught C/C++ first, and I remember the concept of mutability and object identity being not at all difficult. Without being able to refer to fundamental structures and concepts, I usually just exclusively teach students non-mutable patterns (e.g. list.sorted vs list.sort), while pushing them to become much proactive at inspecting and debugging.
- aikah 8y ago> C at the very least teaches the difference between stack and heap memory, a crucial concept obscured by most higher-level languages. Go does that too. C teaches manual memory allocation, de-allocation and pointer arithmetic as well.
- xfer 8y agoNo, it doesn't. Go does escape analysis and allocates stuff on heap if needed.
- majewsky 8y agoNo. In the machine model used by Go, everything is allocated on the heap. The optimizing part of the compiler can then move allocations from the heap onto the stack if it can prove that the allocation does not escape the lifetime of a stack frame.
- geofft 8y agoThere is no difference inside the computer between those concepts. For convenience, many architectures have a single assembly instruction for taking one register (called the "stack pointer"), adjusting it by a word, and moving a register to the address at that word, and a corresponding instruction to move data back to a register and adjust it in the other direction. That's the extent of the abstraction. You can implement it with two instructions instead of one, and then you get as many stack pointers as you want. Zero, if you want. There is no "heap" on modern OSes. There used to be a thing called the program break, beyond which was the heap. It's almost meaningless now. You ask for an area of virtual memory via mmap or equivalent; it is now one of several heaps you have. And you can pass around pointers from all your stacks and all your heaps in the same ways, as long as they remain valid. You need to understand this in order to understand how thread stacks work (you typically allocate them via mmap or from "the heap"); how sigaltstack works and why you need it to catch SIGSEGV from stack oveflows; how segmented stacks (as previously used in Go and Rust) work; how Stackless Python works; how to share data structures between processes; etc.
- jpindar 8y agoFor your definition of 'computer', perhaps. Many microcontrollers have the stack defined by the hardware.
- simonh 8y agoLeaning how microcontrollers work is not the same as 'learning how the computer works' in general, which is the subject at hand.
- geofft 8y agoAnd some, such as RISC-V, have no predefined stack pointer at all. (Push and pop are implemented by doing them manually; call is implemented by the jump instruction optionally taking an argument for a register to use as the stack.) C, at best, teaches you the C abstract machine, which supports both of these concrete implementations equally well.
- tptacek 8y ago
- XMPPwocky 8y agoHere's the C99 standard: http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1256.pdf There are no occurrences of the words "stack" or "heap" in this document. What the spec actually discusses is "storage durations". Now, in many cases you can say, well, "automatic storage duration" means it's on the stack, but that's not something C has any opinions about. If you want to know about the stack and the heap, saying "learn C, and then learn how these abstract C concepts map onto the stack and the heap" might not actually be the best way to figure this stuff out. What actually ends up happening, in my experience, is that to figure C out you have to get a decent mental model of how the stack and heap work, and then, from that, say "automatic storage duration and malloc/free are basically just the stack and the heap". I learned calculus as a kid because I needed it for an online electronics class I was taking. But I'm not going to recommend that folks take electronics classes so they learn calculus! (that said- having a motivation to learn something, having an application in mind, a problem you want to solve... certainly seems to make learning easier.)
- gdwatson 8y ago"C" doesn't just include the spec but also the customary semantics [1] of the language. The customary semantics certainly include the stack and the heap. [1] https://arcanesentiment.blogspot.com/2014/12/customary-semantics.html https://arcanesentiment.blogspot.com/2014/12/customary-seman...
- drb91 8y agoPeople don’t learn C by learning the spec, and virtually every c implementation and runtime I know, it uses a stack and heap. Oddly you seem to recognize this, so I’m not sure what your point is.
- bunderbunder 8y agoAt some point, these conversations seem to always turn into a contest to see who can be the most pedantic. Which I think is pretty fun - and pretty well in the spirit of the original article - but that's me, and I can't fault anyone for being turned off by it. 's funny, I am certainly aware of having, at some point, at least skimmed over the C99 standard encountered the concept of a storage duration. But, aside from that brief few hours, virtually the entirety of my C-knowing career has been spent thinking and talking in terms of stacks and heaps. Meanwhile, in my .NET career, I really did (and, I guess, still do) feel like it was important to keep track of how .NET's distinction is between reference types and value types, and whether or not they were stack or heap allocated was an implementation detail.