17 ms·
C Is Not a Low-level Language (2018)
- johnklos 5y agoThis is a rewording of the original title, which is: C Is Not a Low-level Language Your computer is not a fast PDP-11. "Trying to expose a PDP-11" is misleading here, because how it's written in this title suggests that C is not a low level language because it fails at exposing a PDP-11. Rather, the article suggests that modern processors are made in a way to expose abstractions which are similar to a fast PDP-11, which lacks real ways to represent their true complexity. It's an interesting article, but this misleading title might give the wrong idea.
- nanodano 5y ago> C Is Not a Low-level Language Anymore Pretty sure C was always considered a high-level language.
- rcoveson 5y ago"High" and "low" are relative adjectives. The meaning of "high-level language" has changed. C was considered a high-level language, and it is now considered a low-level language. Not by everyone, of course. There are still a pair of definitions for "high-level language" and "low-level language" that draw the line right above assembly. I won't say "nobody" uses those definitions anymore; lots of people learned them and many still use them. I will say that it is pointless to act as if those are the only definitions of the terms anymore.
- BoorishBears 5y agoPeople don't call C high-level, but I also don't see people call it low-level even in a casual setting with newer programmers. Instead I see it called a system-level language.
- eesmith 5y agoKernighan and Ritchie referred to C as a 'relatively "low level" language' in their 1978 book.
- BoorishBears 5y agosounds like system language is a nice way to say "relatively low level" then?
- eesmith 5y agoK&R write: > It has been closely associated with the UNIX system, since it was developed on that system, and since UNIX and its software are written in C. The language, however, is not tied to any one operating system or machine; and although it has been called a “system programming language” because it is useful for writing operating systems, it has been used equally well to write major numerical, text processing, and data-base programs. https://archive.org/details/TheCProgrammingLanguageFirstEdition/page/n7/mode/2up?q=system https://archive.org/details/TheCProgrammingLanguageFirstEdit...
- BoorishBears 5y agoSo it sounds like they're endorsing that concept, and just don't want it to be a limiting term in terms of what people expect in regards to portability and scope? "System level" does that just fine right? There's not much confusion about if C is tied to Unix anymore after all...
- eesmith 5y agoI really don't understand the aim of your inquiry. Yes, I see it called a systems programming language. But unlike you, I see people call it low-level. The easiest counter-example was to point to K&R, which was my textbook in college. (Yes, pre-ANSI). And there are many people who still say that, as I found in a quick Google Scholar search: ] Although the Java platform has been used as a multi-language platform, most of the low-level languages (such as C, Fortran, and C++) - (2016) https://dl.acm.org/doi/pdf/10.1145/2998415.2998416?casa_token=YFdopIGDfQ0AAAAA:L-6DD9hqqFdXHqlziwugfgUN5Uq1mO3we2ypQ2bNOafgsgkbvl4cFAJCx_H2BvJ6sXzeVhsFWZ2A https://dl.acm.org/doi/pdf/10.1145/2998415.2998416?casa_toke... ] Lifting these restrictions is primar-ily motivated by our desire to target low-level languages, such as C with pthreads - (2011) https://dl.acm.org/doi/pdf/10.1145/1929553.1929558?casa_token=ZdfRD-LQVE0AAAAA:Fp8XUJWmt0JAVJRSDUcQoxbaFZ0GE45unmFJHgafNbWPW0uEOA8HoYXxQ2GVKRdKuBKPyJSQc3uF https://dl.acm.org/doi/pdf/10.1145/1929553.1929558?casa_toke... ] Use-after-free vulnerabilities have plagued software written in low-level languages, such as C and C++, - (2020) https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9152661&casa_token=bnR0QcL-O_sAAAAA:TW0lKnWSJxoWZQeuMYuUfK0O6i_C-nVHNIEPsKxtj_jw_Ob9B5-95BEPOBU3GasDDtzhFvowiGxt https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=9152661... Now that you've seen people call it low-level, you can't truthfully write a comment like you did at https://news.ycombinator.com/item?id=29710906 https://news.ycombinator.com/item?id=29710906 .
- eesmith 5y agoI think I'm confident in saying that K&R saw C as lower-level language. As you say, it is relative [1]. I just don't think enough people considered C to be a high-level language (given that Smalltalk, APL, and Lisp were about) to make your broader characterization that "C was considered a high-level language." Here's my reasoning: From "The C Programming Language" book (1st. ed., 1978) at https://archive.org/details/TheCProgrammingLanguageFirstEdition/page/n5/mode/2up?q=level https://archive.org/details/TheCProgrammingLanguageFirstEdit... we can read 'C is not a "very high level language"' (p. ix) and 'C is a relatively "low level" language' (p. 1).[1] They describe what "low level" means to them: "This characterization is not pejorative; it simply means that C deals with the same sort of objects that most computers do. namely characters, numbers, and addresses." And on page 2 we see how they don't regard C as the lowest level: "Of 13000 lines of system code, only about 800 lines at the very lowest level are in assembler." I also found "The C Programming Language" paper in The Bell System Technical Journal (1978) saying "All three languages [BCPL, B, and C] are rather low-level", at https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=6770408&casa_token=eqKV_z4PEwIAAAAA:UfW87DtWHfhOlMr05bvdoXzbi1Zn9E2BKbpgD9Gs6PCOZg8Up99sk9zVqtsa6PYkrc0z7HBZz18Q https://ieeexplore.ieee.org/stamp/stamp.jsp?arnumber=6770408... . Now to the [1], I found the paper "Implementing LISP in a high‐level language" from 1977, where that high-level language is BCPL, which is a precursor to C, so clearly a good number of people at the time would have considered C a high-level language, at the very least in the context of developing a Lisp.
- TheOtherHobbes 5y agoK&R are not the last word on this. They made their comment in 1978, and now it's 2021, and computing is very different. "Characters, numbers, and addresses" are very much not what CPUs deal with internally today. Most languages no longer reference addresses directly, and "characters and numbers" live behind abstractions of their own. The point is that C assumes a certain model of computing that was baked into both hardware and software from the late 70s onwards. That model has been superseded, but hardware and software still lose a lot of cycles emulating it. The claim is that this is both inefficient and unnecessary. But the advantage of the C model is that it's simple, comprehensible, and general. If you expose more of what goes on inside a modern CPU, programming becomes more difficult. If you build a CPU optimised for some specific other language abstractions you bake other assumptions and compromises into the hardware, and other languages become less efficient. So if you want to replace the C model you'd first have to define an industry standard for - say - highly parallel languages with object orientation. That is not a small or simple project. And previous attempts to tie hardware to more abstract languages haven't ended well. So C persists not because it's high or low level, but because it's general in a way that other potential abstractions aren't. This is not to say that alternatives couldn't be both more general and more performant. It's more a reminder that designing performant alternatives is harder than it looks, and this is not a solved problem. My guess (FWIW) is that nothing credible will emerge until radically new technologies become more obviously better for general purpose computing - whatever that looks like - than current models.
- ncmncm 5y agoC is the lowest-level language in common use, short of assembly language. C lacks any high level abstractions. All the abstractions it does offer are hiding register and stack slot assignments (as local variables), code entry point addresses (as function names), ALU instructions (as operators), branching (as control-flow statements), and address arithmetic (as pointer operations). All of these are low, machine-level abstractions. C was never a high-level language, even from its first day. It was specifically intended as a portable assembly language, by someone used to coding assembly language, to use porting an OS coded in assembly language to a new target host.
- charcircuit 5y ago>C lacks any high level abstractions macros
- pjmlp 5y agoAnd structures, unions, pseudo-meta programming via the macro processors, no exposure to IO unless on a CPU with MMIO. JOVIAL and Algol dialects were also designed for creating OSes and no one calls them low level.
- wott 5y ago> And structures, unions, pseudo-meta programming via the macro processors, Those exists in macro assemblers, for they are extremely thin abstractions, no thicker than jumping to a label instead of jumping to an absolute or relative address. > no exposure to IO unless on a CPU with MMIO. Well, since not all processors have I/O instructions (or dedicated I/O pins), the easiest way to implement portability is simply to not provide a direct access to them in the language, and let library functions handle it.
- pjmlp 5y agoWhich kind of proves the point C doesn't provide all the necessary capabilities for a systems programming language. As for macro Assemblers, IBM i one supports OOP constructs, so are OOP languages now low level?
- Jensson 5y ago"Low level" is relative. The article says that there doesn't exist any "low level" languages that programmers can use, this isn't a very helpful definition. If we go by the languages that programmers actually have access to, then machine code is as close as you get to the metal, and C maps very well to machine code. So by any reasonable definition C is a low level language for programmers. For a hardware engineer who works on CPU architecture it is of course different, but we are talking from a programmers perspective here.
- whatatsentyways 5y agoGood take - defining a "low-level language" feels like trying to define a "cold temperature". It's all very relative. We could say that a temperature is "freezing" if it is under 0C, and "boiling" if it is over 100C. But it's hard to nail down "cold" or "warm", as any group sharing a thermostat will tell you. You can easily place arbitrary assembly commands or memory values in C code. Plenty of embedded codebases are littered with asm blocks in performance-critical areas. It's hard to see it as a high-level language in the age of javascript/python, but maybe the overton window has shifted.
- to11mtm 5y agoYeah IDK. I know in college, a lot of my profs referred to C as a 'mid level' language (or by others as a 'systems' language), C# 1.2 and Java were 'high level'. They really only considered ASM as a low level, but that was almost 20 years ago.
- drran 5y agoC is a 3-rd level of abstraction language. Currently, there is no 4-th level of abstraction, so C is a high-level language by definition of «level of abstraction». Language levels of abstraction: 1. Machine code 2. Assembler 3. A high-level language C does allow low level things, e.g. access of machine registers or embedding of assembler or machine code, but it is also capable of quite high level of abstraction. Some of 3-rd level languages allows higher level of abstraction, or hide low level abstractions, e.g. memory management, stack, byte order, bits per number, etc., hover none of them improves programmer productivity by an order of magnitude.
- mghfreud 5y agoI am lost here, the mentioned bugs are a result of optimizations like speculative execution, branch prediction, prefetching etc. These are language independent optimizations. For example, any language (that allow for loop like constructs) compiled to intel machine code and executed on intel processor will be exposed to these bugs, it is not C specific. Am I missing anything?
- spijdar 5y ago> any language (that allow for loop like constructs) compiled to intel machine code and executed on intel processor will be exposed to these bugs, it is not C specific. Well, that's kind of the point, that Intel/x86 and most/all modern processors implement an abstract machine that's basically made for C, papering over the underlying instruction parallelism and absurdly complex memory model with all kinds of crazy front-end decoder business to allow the CPU to ingest that machine code and pretend like instructions are executed in order, with C-style control flow. You could (in principle) prevent these sorts of bugs by creating a new kind of machine, but that machine would be incapable of running C software, at least efficiently. There are several ideas being alluded to here, another is the idea of directly exposing the underlying instruction level parallelism -- that's been attempted before in VLIW processors like Intel's Itanium chips. You could make the argument a big part of their problem was at the compiler level, trying to map C-style semantics to the CPU, while maybe a different language/compiler would have extracted more performance. Trying to summarize the author's idea, modern CPUs have a lot of hidden potential behind a restrictive "virtual machine". If that layer were stripped clean, we could (the idea goes) get more performance and parallelism, and potentially more security, at the cost of compatibility/interoperability with legacy software.
- dahfizz 5y ago> Intel/x86 and most/all modern processors implement an abstract machine that's basically made for C, papering over the underlying instruction parallelism and absurdly complex memory model with all kinds of crazy front-end decoder business to allow the CPU to ingest that machine code and pretend like instructions are executed in order, with C-style control flow. The issue is that none of this has to do with C, really at all. C relies on the semantics exposed by the machine code. The ISA does not expose speculative execution or pipelining. C, and asm, and literally all software conforms to the ISA because that's all there is. Calling out C specifically is just clickbait, IMO. The author makes a great point about how the x86 ISA may not be a great abstraction for modern CPUs.
- pmontra 5y agoAs hinted by the article LLVM IR [1] is a lower level language and yet it's only intermediate as per the i in IR. And it's true that the actor model makes writing parallel programs easier. I tend to use queues and message passing when I write multi threaded programs in sequential languages like Python or Ruby. That's easier to do in a language like Elixir. Unfortunately when I work with Elixir I'm a little discouraged by all the boilerplate needed to make supervisors and GenServers work. I think there is a lot of room for improvement for a higher level language that makes most of that disappear. [1] https://llvm.org/docs/LangRef.html#instruction-reference https://llvm.org/docs/LangRef.html#instruction-reference
- styluss 5y agoI'm not sure if it's the appropriate solution but have you looked at higher level abstractions in elixir, like Flow, Broadway, GenStage?
- riskneutral 5y agoThe Cell processor was a very different architecture from x86. It sacrificed cache coherency and required the programmer to manually manage each core's cache, in exchange for state-of-the-art performance. This was all done in C (although FORTRAN compiler was also available, of course). The Cell processor simply introduced new intrinsic functions to the C compiler, to allow the programmer to access the new hardware functionality. It all works perfectly fine with the rest of C, although people felt it was too difficult to program and the architecture quickly went extinct. NVIDIA GPUs are also innovative hardware, mentioned in the article, and CUDA is also just an extension of C. CUDA is wildly popular, and lots of higher level abstractions had been built on top of it. The only thing lower level than CUDA is the NVVM IR code which is generated by the C compiler (eg. LLVM NVVM backend) and is only compiled into final machine code by the GPU driver at run-time. So C is the lowest level. The problem doesn't lie with the language, it lies with the x86 processors and different trade-offs that companies like Intel must make, such as trying to sell processors to developers who have been instructed by their employers to be productive and use a "safe" and high level language (e.g. Java CRUD application developers, or JavaScript web developers, etc). edit: typos
- tubby12345 5y agoNVVM IR compiles down to PTX which then is compiled by the driver to a shader language (or something like that).
- qayxc 5y ago> NVIDIA GPUs are also innovative hardware, mentioned in the article, and CUDA is also just an extension of C CUDA uses a completely different programming model from C. There is no such thing as a C virtual machine behind CUDA and just because the syntax is identical (to make adoption easier), doesn't mean semantics are. > The problem doesn't lie with the language, it lies with the x86 processors and different trade-offs that companies like Intel must make You are ware of the fact that the mentioned UltraSPARC Tx CPUs are also highly susceptible to Spectre? These CPUs feature up to 8x SMT ("hyperthreading" in Intel jargon) and thus are facing the same issues as x86 when it comes to parallelism and speculative execution. The problems are evident across hardware architectures.
- AceJohnny2 5y agoIt's really fun (?) to work with hardware designers, for whom even the registers that the code accesses is considered "high-level". Abstractions, all the way down... even our digital bits are a joke to the analog designers.
- deleted 5y ago[deleted]
- protoman3000 5y agoThanks for this interesting read. Say a platform superseded that C platform the article is describing, allowing for an unleash of power and parallelism in computing, what are the implications for Linux and other operating systems?
- qayxc 5y agoI doubt that outside of special cases this would actually provide significant benefits. Suitable languages already exist (see Erlang), but the fact of the matter is that a vast array of problems don't benefit from parallelism or aren't parallelisable at all. Not to mention that a good chunk of the benefits would be negated by the increase in coordination and synchronisation between parallel tasks.
- usrbinbash 5y agoThe Problem is not with C alone however. Speculative Execution, branch prediction and look ahead to the next 25 instructions, wasting huge amounts of power,...I mean, what? The article even mentions that there is another way: > In contrast, GPUs achieve very high performance without any of this logic, at the expense of requiring explicitly parallel programs. Yes, C doesn't support that very well. But it could, and other languages, namely Rust, Go & Julia already can. So maybe it's time to do in CPU design what Go did in language design, and hit the brakes on complexity? We don't need smarter processors, we need processors that can do high throughput on many execution units, and languages that support that well.
- jcelerier 5y agoPlease no :( unparallelizable tasks are already slow enough. My guitar effects rack (where effects all have to be processed one after each other, by design) uses barely less CPU% in a 2020 computer than in a 2011 one and it is extremely frustrating.
- usrbinbash 5y ago> uses barely less CPU% in a 2020 computer than in a 2011 one and it is extremely frustrating. But if that's the case, what's the point in all that extra-complexity in the CPU, if in the end the benefits seem to be miniscule?
- jcelerier 5y agoall this "extra complexity", branch prediction, pipelines, multiple levels of cache, speculative execution was mostly there since the late 80s, 90s in CPU design ; the Pentium pro already had all of this to some level. The last decade was in large part about more SIMD and more cores and it's been a real PITA when your workflow does not benefit much from it because the state at t depends on the state at t-1. But the improvement of these features is definitely not negligible ; at the beginning of the SPECTRE / Meltdown / ... mitigations the loss of performance was double-digit big% in some cases.
- phendrenad2 5y ago"Assembly isn't a Low-Level Language: Your heterogeneous multicore Apple M1 with integrated GPU and multi-tier SRAM cache isn't a 1970s PDP-11 minicomputer, you can't just MOV RAX, EAX and expect it to work, you complete and utter jackwagon!"
- smlckz 5y ago> In C, a read from an uninitialized variable is an unspecified value and is allowed to be any value each time it is read. This is important, because it allows behavior such as lazy recycling of pages: for example, on FreeBSD the malloc implementation informs the operating system that pages are currently unused, and the operating system uses the first write to a page as the hint that this is no longer true. A read to newly malloced memory may initially read the old value; then the operating system may reuse theunderlying physical page; and then on the next write to a different location in the page replace it with a newly zeroed page. The second read from the same location will then give a zero value. What? What is the benifit of such behaviour? What does other OSes do in this regard?
- bodhiandphysics 5y agoLots of programs malloc a lot of memory, and do nothing with it for a while. This allows the os to wait for a low load time to handle memory allocation.
- pm215 5y agoIs there much benefit from delaying the zeroing to first-write rather than first-read (which I think is effectively where Linux does it)?
- bodhiandphysics 5y agoProbably not... but both ways are fine.
- astrange 5y agoI think the article is just incorrect and every system uses allocation on first read.
- veltas 5y agoC's pre/post-increment is from B which was designed for an older arch, not PDP, and B still had the pre/post increment and decrement. It's now a well known misconception that C was based on the PDP's instructions, it doesn't hold water with the facts. C did redesign for one thing on the PDP and that's byte addressing... and we're still using byte addressing most places, and frankly if you don't then C isn't incapable with that.
- shakow 5y ago> and we're still using byte addressing most places Which is a masquerade in itself, as in the silicon, addressing works at the memory line level.
- bodhiandphysics 5y agoThe cpu bus is what’s important. Bus addressing us at the byte level
- shakow 5y agoOn modern CPU, byte-level addressing is but smoke and mirrors for what is a fetch of a line-sized memory chunk followed by a mask-and-shift.
- bodhiandphysics 5y agoNot at the ISA level. Programmers don’t have access to the smoke and mirrors besides some cache management stuff
- p_l 5y agoDepends on the cpu specific, and a lot of non-x86 designs made it explicit that memory is not byte addressable without special steps. This makes those architectures incompatible with latest C and C++ though, because they require simultaneous, concurrent, atomic access to bytes at a time
- kovacs_x 5y agoOne should always think of a C as high level Assembler. Not less, not more. Everything else (parallel programming, threading, ...), are "higher" level paradigms, where C "robustness" is more of an obstruction, not a help. Imo, from hw designers perspective C is a language as "high" as it goes, when for a software engineers it's often "as low as it goes".
- lproven 5y agoHave you RTFA? Because that is exactly the point that the article refutes.
- Const-me 5y ago> which attempt to hide latency It does exceptionally good job at these attempts. If you think manually managed caches are fun, read [1] for an illustration what amount of efforts is required to sum an array for an architecture where on-chip RAM is manually managed. Another interesting case was Cell CPUs in PS3, I don't have hands on experience but I've read that it was equally hard to develop for. > A low-level language for such processors would have native vector types of arbitrary lengths. A low-level language would have native vector types of exactly the same lengths as underlying hardware. "arbitrary" is overkill unless the CPU supports arbitrary-length vectors. Despite not specified as a part of language standard, all modern C and C++ implementations support these things. Specifically, when compiling into AMD64 instructions, the compilers implement native vector types, and vector intrinsics, defined by Intel. Same with NEON, all modern compilers implementing what's written by ARM. > you must be able to compare two structs using a type-oblivious comparison (e.g., memcmp) Using memcmp on structures is not necessarily a great idea, these padding bytes can be random garbage, it's not specified. > with enough high-level parallelism, you can suspend the threads.. The problem with such designs is that C programs tend to have few busy threads. Not just C programs. User input is serial, it can only interact with 1 application at a time. Display output is serial, it delivers a sequence of frames at 60Hz. Web browsers tend to have few busy threads because JavaScript is single threaded, also streaming parsers/decompressors/decryptors are not parallelizable. > ARM's SVE (Scalar Vector Extensions)—and similar work from Berkeley—provides another glimpse at a better interface between program and hardware. Just because it's different does not automatically make it better. The main problem with scalable vectors, it seems to be designed for problems CPUs no longer solving. For massively parallelizable vertical-only FP32 and FP64 math, GPGPU is the way to go, an order of magnitude faster while also being much more power efficient. CPU SIMD is used for more than vertical-only math. One thing is non-vertical operations i.e. shuffles, trivial use case: transpose a 4x4 matrix in 4 registers. Another one is operations on very small vectors, CPUs even have a DPPS instruction for FP32 dot product. For both use cases, scalable vectors make little sense. > a garbage collector becomes a very simple state machine that is trivial to implement in hardware People tried that a few times, first with Lisp, then with Java chips. General-purpose CPUs were better. > Running C code on such a system would be problematic, so, given the large amount of legacy C code in the world, it would not likely be a commercial success. nVidia did precisely that, made a processor designed purely for compute speed. I wouldn't call them a commercial failure. [1] https://www.nvidia.com/content/GTC-2010/pdfs/2260_GTC2010.pdf https://www.nvidia.com/content/GTC-2010/pdfs/2260_GTC2010.pd...
- dash2 5y agoPrevious HN discussions with many comments: https://news.ycombinator.com/item?id=16967675 https://news.ycombinator.com/item?id=16967675 https://news.ycombinator.com/item?id=21888096 https://news.ycombinator.com/item?id=21888096
- flohofwoe 5y agoThis one caught my eye: > for example, you must be able to compare two structs using a type-oblivious comparison (e.g., memcmp), so a copy of a struct must retain its padding. This definitely doesn't work in the real world because the padding bytes will contain random junk which isn't copied along in some situations, depending on the compiler and optimization level. Also, IMHO what the article calls "low level" might be important for compiler writers, but isn't really all that relevant for most programmers when the comparison is to "high level" languages like Java, C#, Javascript or Python. In my mind, the most important property of a low level langauge is to provide explicit control over how data is layed out in memory, this is usually an afterthought in high-level languages, if possible at all. Or more generally: how much explicit control does the language allow before the programmer hits the "manual optimization wall". In that sense C is fairly high level, especially without non-standard extensions, but still much lower level than most other programming languages. I think there is definitely room for more experimental languages between C and assembly.
- rightbyte 5y ago> In that sense C is fairly high level, especially without non-standard extensions, but still much lower level than most other programming languages. In practice you are using gnu c etc. The Stackoverflow consensus that you are supposed to stick to the standard no matter the complexities of the workarounds is rather annoying and seem to be quite prevalent.
- sharpneli 5y agoThe reason for sticking to standard is when inevitably someone will try to compile it with another compiler. It’s far easier just to stick to the spec instead of fixing non standard code. For some reason it has been me several times doing the fixing as original dev thought it’s completely fine. I hope to save others the pain.
- flohofwoe 5y agoIMHO the only practical solution to this problem is to compile and test the code at least on the popular compilers (e.g. GCC, Clang and MSVC), which is quite easy today with CI services like GH Actions. The standard also often doesn't tell what features are actually supported by different compilers (e.g. MSVC famously will never be C99 compliant, but eventually - really soon now! - C11 compliant) - so the language standard is in reality more like a recommendation of what features are more likely to work across compilers than others. Finally, even standard compliant code may still trigger a lot of warnings, and those warnings are different on different compilers or different versions of the same compiler, so testing on different compilers is needed anyway to cleanup warnings.
- noobermin 5y agoThis article is my go to url when arguing on the internet with people who are under the illusion that "C is portable assembler" when it really isn't and their mental model is actually not what a computer actually does today (or has performed in the past few decades).
- pjmlp 5y agoAnother way is to ask them to describe how to perform certain systems programming tasks with the restriction that it was to compile under pure ISO C mode. The answer will always be external Assembly.
- dunemaster 5y agoThis article could have been 1/8th of its length and the message would still be clear. Modern writing is vague, overly detailed and inelegant.
- lproven 5y agoNot really; as evidence, look at the number of comments here that failed to get the point. When you present a viewpoint to people whose profession and living depend on believing something contrary to it, it's necessary to present a lot of evidence and solid reasoning to get even a small number of the smartest of such people to consider your point.
- deleted 5y ago[deleted]
- marcodiego 5y agoLooks like C being Low-level or not needs a precise or formal definition of low-level language. Without that, it falls down to opinion.
- lproven 5y agoI am wondering if this excellent essay has surfaced again because I just tweeted it in reply to a popular Twitter account. I dispute your conclusion, and this is the reasoning, as expressed in the article: "High level" is tricky to define, because high is a relative assessment. But "low level" has a clear, agreed meaning: relatively similar to the machine's instruction set and architecture; close to the metal; comparable to assembly language. And the point of the article is that C is close to the architecture of a PDP-11. Modern CPUs are nothing like the PDP-11 and haven't been for a third of a century or more. C models the architecture of a 1970s minicomputer, and 21st century computers are nothing like 1970s minis – they just run similar OSes. If C is not close to the real architecture, then it's not low level. The fact that there's nothing mainstream which is closer is irrelevant. The C programming model is nothing like modern multicore SIMD superscalar 64-bit CPUs with out-of-order execution, branch prediction etc. If it isn't close to the metal, then it isn't low-level. C is neither any more. QED.
- zaptheimpaler 5y agoIs there a language that exposes the stuff below assembly? Like assembly language presents a nice sequential ordered view of processors as if they execute instructions 1 by 1, but we know the reality is quite different - each instruction is many micro instructions, they compute data dependencies and parallelize accordingly, pipeline & predict heavily etc. We do so much to fit async data dependent computation into sequential models, only for that to be translated back into async/parallel by the CPU. I wonder what that kind of PL would look like?
- fault1 5y agoperhaps HDLs like (system)verilog and vhdl? then you truly are interacting with the architecture and you care much more about things like timing, clock cycles, etc.
- kazinator 5y agoThis article presents a false premise. Intel (and other) processors present a serial programming model in spite of parallelism under the hood because that is required for stable semantics in assembly language programming, and for the instruction set architecture to be a stable target for any higher level language whatsoever. It's not because of the expectations of the C programming model. The unoptimized, instruction by instruction fetch-decode-execute model of the instruction set pins down what the code means, which is super important, otherwise there is chaos. Moreover, machine language executables must continue to work across evolution of the architecture family. The way an new Intel processor is today has as much to do with C compilers as it does with the need for someone out there to run MS-DOS or Windows 95. Compilers could better deal with chaos at the architecture level, because breakages at the architecture level can be treated as a new back-end target, and code can be recompiled. It's the code that doesn't get recompiled that you have to worry about.
- kaba0 5y agoBut converting (even just-in-time) between two architectures is not that hard — if every new code could get some better performance/efficiency at minimal overhead for “legacy” applications, it may well worth it.
- dev_tty01 5y ago>Moreover, machine language executables must continue to work across evolution of the architecture family. The way a new Intel processor is today has as much to do with C compilers as it does with the need for someone out there to run MS-DOS or Windows 95. Apologies, but I think this belief that compatibility must be maintained is false. Apple has made three incompatible binary architecture transitions and dealt with the issues via emulation. Each time, the performance gains from the new architecture have masked the inefficiencies of the emulation layer until applications could be rebuilt. It just takes a willingness to say no to legacy compatibility. Microsoft is finally trying to take a similar step with WinARM. I suspect the x86 architecture will get relegated to the dust bin within a few more years. The instruction set is just too polluted and chaotic at this point. As an example, the Apple M1 instruction decoder is much wider than x86 and part of why that was practical to implement in a power efficient way is that the M1 instruction set is much less variable in length.
- throwingawayyou 5y ago
- JoeAltmaier 5y agoMaybe this doesn't matter so much. Remember, the cpu may be re-writing your code and re-ordering many operations. The latest Intel processors can examine your code and write new microcode to do it more efficiently. Heck, even identifying a fault to an instruction in 'your' code has become problematic!
- avidphantasm 5y agoEffing great article. I am starting down the path of learning rust and wondering how its mutable-first design and ownership model alleviate some of the problems identified in making C fast on contemporary machines.
- wly_cdgr 5y agoPretty sure K&R calls C a high level language. Just a matter of perspective, innit: a high level language to assembly programmers, a low level language to .NET/JVM/web programmers, and prob something like a lower-mid-level language to someone looking at the whole tower from a distance
- jleyank 5y agoI have an old button that says “C combines the power of assembly language with the flexibility of assembly language.” Might have changed now, but it was a humorous yet valid observation then.