7 ms·
A lot of people have a misconception that C is close to the way hardware works. The reality is that hardware engineers jump through lots of hoops so that C prog
by yogthos 7y ago
A lot of people have a misconception that C is close to the way hardware works. The reality is that hardware engineers jump through lots of hoops so that C programmers can keep pretending that they're coding against a really fast PDP-11. Not only that, but these contortions directly lead to vulnerabilities like Meltdown and Spectre because memory representation in C doesn't map well to modern hardware. C family of languages is basically holding us back from utilizing current day hardware safely and efficiently. This [1] is an excellent essay on the topic.
[1] https://queue.acm.org/detail.cfm?id=3212479 https://queue.acm.org/detail.cfm?id=3212479
- x3ro 7y agoThanks! Comments like these, especially backed by good sources, are why I keep coming back to the often pretty messy comment sections of HN :D
- pmarin 7y agoMeltdown and Spectre are hardware bugs.
- aduitsis 7y agoGood comment and article, thanks! One thing only, the phrase "The quest for high ILP was the direct cause of Spectre and Meltdown" is slightly exaggerated. One might say ILP was rather a remote indirect cause, not the direct cause. Blaming it on C and ILP maybe is kind of far fetched. That isn't to say that the article doesn't have a point though, far from it.
- codebolt 7y agoAny idea what a low level language that was designed for today's hardware would actually look like?
- yogthos 7y agoGPU shaders are a good example.
- dodobirdlord 7y agoLLVM IR, but it’s also not designed for humans to write without tool assistance.
- nickelpro 7y agoWhat a load of crap Without cache coherency and ILP, programming in any language would be insane. It's not like programming in x86_64 assembly suddenly opens a world of possibilities because its "truly low-level". You gain very little extra control over a given platform by switching to assembly over C, that's what we mean by "low-level". C maps cleanly onto the instruction sets provided by chip manufacturers. It provides the option to the programmer to optimize structures for use in vectorization if they so choose, or to optimize for some other objective like size for a binary wire protocol or limited memory space. The very nature of having a choice about memory layout of structures and the ability to cleanly link with the platform ABI is what makes C low-level. Obviously the inner-workings of a modern CPU don't map cleanly to the C virtual machine. However, there's no convincing evidence that greater control over cache invalidation is what's holding back performance of those CPUs.
- aspaceman 7y agoWhile I also disagree that C is “holding things back”, I don’t think their comment is a “load of crap”. Talk like that is unhelpful and quite frankly non-technical and unprofessional.
- aportnoy 7y agoLose the leading sentence, your comment is great otherwise.
- kjhrklewiou 7y agoIn GPU programming (CUDA for example), every time you allocate memory you need to explicitly specify where (general memory, L3, L2, L1, register). Because C doesn't support this, they added language extensions. So C is too high level for GPU programming, and needed to be extended.
- sigjuice 7y agoIf finer-grained cache control is needed, then it is no big deal to invoke the appropriate compiler intrinsics (if available) or write your own with inline assembly. My preference is to put these sorts of things in a separate .S file.
- 7y ago
- Abishek_Muthian 7y agoSimilar reasons are given for Golang design in their comparison to C language. e.g. >Why is there no pointer arithmetic? >Safety. Without pointer arithmetic it's possible to create a language that can never derive an illegal address that succeeds incorrectly. Compiler and hardware technology have advanced to the point where a loop using array indices can be as efficient as a loop using pointer arithmetic.[1] [1]https://golang.org/doc/faq#no_pointer_arithmetic https://golang.org/doc/faq#no_pointer_arithmetic
- rightbyte 7y agoBut there is pointer arithmetic in Go, in the "unsafe" package. Like with generics the Go authors want to decide where and when these are used, but they actually made it possible for mere users of Go to use pointers freely, since it's badly needed from time to time, unlike generics which they hide fully.
- foldr 7y ago>Like with generics the Go authors want to decide where and when these are used, I wish this meme about Go and generics would die already. C allows you to define an array of int and and an array of char and have those be two different types. Go allows you to do this with slices and maps as well, because slices and maps are also built in types in Go. This is not "generics".
- Nullabillity 7y agoYes, C has (very restricted) generics too. No, Go does not need to repeat all of C's mistakes.
- foldr 7y agoI think it's more useful to think of "generics" as applying to type systems that allow abstraction over types. C and Go crucially don't allow you to define a function that, say, appends an element of type T to an array of T. That's where things start to get complicated. C and Go don't have a restricted version of that [1] - they just don't have it at all. [1] With the largely irrelevant exception of the C11 _Generic stuff.
- twoodfin 7y agoI’m sympathetic to the argument that C isn’t realistically a “high-level assembler” any more, but if there is low-hanging performance fruit available for a language free to dispense with C’s PDP-11-flavored abstractions, I haven’t seen practical examples of it. If anything, more modern languages (eg Java) have to contort their data representations to build, say, “structs of arrays” that are highly efficient on modern CPUs (and trivial to express in C!) I’m very curious to hear of any recent languages that are designed expressly with “mechanical sympathy” in mind.
- aratakareigen 7y agoHow are structs of arrays more natural in C than in Java?
- nemo1618 7y agoRegarding your SoA example, Jai has explicit support for switching between SoA and AoS without having to rewrite everything: https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md#data-oriented-structures https://github.com/BSVino/JaiPrimer/blob/master/JaiPrimer.md...
- polityagent 7y agoI believe jblow removed this in more recent versions.
- ChrisSD 7y agoThe trouble is both processor instructions and compilers have been optimized for C (well C and FORTRAN). So no matter how good or bad C is, we're mostly "stuck" with its PDP-11 computing model unless someone does a lot more work than just making a new programming language.
- user234683 7y agoThe ISPC language by Intel is designed to give enough information to the compiler so as to allow auto SIMD-vectorization of programs [1]. It opts for an explicitly parallel model of programming, unlike C [2]. It also has easier support for SOA and AOSOA [3]. [1] https://ispc.github.io/ https://ispc.github.io/ [2] https://ispc.github.io/ispc.html#the-ispc-parallel-execution-model https://ispc.github.io/ispc.html#the-ispc-parallel-execution... [3] https://ispc.github.io/ispc.html#structure-of-array-types https://ispc.github.io/ispc.html#structure-of-array-types
- rightbyte 7y agoThe author seems to trivialize how hard it is to write a compiler that generates efficient code. Like designing a simpler language than C (less general architecture targets) would solve much.
- yogthos 7y agoIt's not about designing a simpler language than C, but rather one that matches what hardware is actually doing better. The example in the article is how GPU programming works. To make the most out of modern hardware we need to change the way we program to embrace concurrency, parallelism, and eschew shared global state entirely. The way FP works is much closer to hardware than the imperative style.
- rightbyte 7y agoI have a hard time figuring out how forbidding concurrent task from communicating would necessarily make them faster. Also, how is FP a more accurate model of eg. AMD64 than imperative style? How would eg. "Clear Global Interrupt Flag" instruction be modeled in FP with no states?
- akra 7y agoI don't know if it is a more accurate model of AMD64/X86 but it may be a better match for the underlying silicon (gates, logic circuits). I can see function pipelines and composition of these in some ways analogous to circuit design. After all those instruction sets in AMD64 are merely an implementation of these. Pure functions and pipelines could model circuits quite well.
- gpderetta 7y agoShared state is not a problem with current hardware, mutable state is also bit a problem. The only issue is with shared state that is mutated from multiple CPUs and that's why the single writer principle is a fundamental rule of multithreaded programming.
- nyc_pizzadev 7y agoI'm pretty certain the CPU engineers at Intel/AMD/etc aren't pulling out K&R 1978 and then telling themselves this is their new reality. All kinds of new safety, virtualization, and ML instructions have been added to CPUs without consent from the "C language". Infact, its Google, Amazon, Apple, Microsoft, and Facebook who are controlling CPU roadmaps!
- FpUser 7y agoI am sure this "misconseption" is what keeping Python programs so fast and efficient comparatively to ones written in C
- jmull 7y agoThat's not quite right. They jump through hoops so that C programs and the programs of all the other languages designed to run in the same execution model run as fast as possible. It's not to indulge C programmers but to support the vast body of existing software. Hardware engineers need optimization targets just liker anyone else, and it's an eminently reasonable one. Also, it's not like loads of improvements not related to the C execution model haven't been made. Demonstrably, the C model is not holding us back. Anyway, if you want to move on from the C execution model, great. Now you need to introduce a practical transition plan, which should include such details as how and why we should rewrite all of the existing performance sensitive software designed to work in the old model.
- inkwater 7y agothe C execution model has demonstrably held us back because the practical transition plan for migrating existing C codebases would be automated translation (of the C Turing tarpit) into sane functional/formal models
- gpderetta 7y agoDemonstrably?
- lidHanteyk 7y agoSure. Foreign function interfaces (FFIs), also known as ctypes, are probably the best thing to point to as glaring examples of how C holds us back. Once we start there, then a spidering network of technologies are highlighted, all surrounding C, from dynamically-linked code objects (DSOs and DLLs) to the required usage of '%' characters for printf-style string formatting via templating. We need to move beyond memory-unsafe paradigms already. Assembly intrinsics aren't great but they're certainly better than C.
- ncmncm 7y agoSorry, who requires % formatting? Never use it, myself, except configuring the date format in my menu bar.
- dang 7y agoOriginal thread about that article in 2018: https://news.ycombinator.com/item?id=16967675 https://news.ycombinator.com/item?id=16967675
- aportnoy 7y agoIsn’t this abstraction presented at the ISA level, not by C? It’s not that C isn’t close to the way hardware works, it’s that the ISA interface presented to C compiler writers isn’t close to how instructions are actually executed.
- gpderetta 7y agoThe computer history graveyard is full of architectures that were supposed to be superior by directly supporting the trending programming paradigm of the day. The current microarchitectures for general purpose computing, that is OoO execution, cache coherent shared memory with a flat memory model, and mostly transparent and coherent caches seems to be optimal. In fact, far from being designed around C, C and siblings had to evolve to support the model well (a memory model, explicit SIMD builtins, support for vectorization and offloading etc). It is entirely possible this is only a local optimum, but I have yet to see a plausible model for a better architecture. It is more likely that, now that silicon is cheap and CPU designers are struggling to find ways to use it, extensions to support higher level languages might be added: more fine grained cache control for message passing, extra tags to help GCs, and more stuff that I can think of.