7 ms·
It's less that the OS is written in C, but more that literally every single interface to literally anything is either written in C, or isn't meant to be used by
by dzaima 5y ago
It's less that the OS is written in C, but more that literally every single interface to literally anything is either written in C, or isn't meant to be used by multiple languages. C is the de facto standard for interacting with anything not written in your language. Window management, I/O, graphics, everything has a C interface. There aren't even any alternatives (besides just sending a list of bytes through a pipe or something, which noone wants to do for obvious reasons).
- ChuckMcM 5y agoI don't disagree, I see an expectation on the part of driver/API providers that you can write (probably in C) and adapter layer that can talk "glorious language" on the input, and then do the naughty bits and talk to the C API on the output. My position is that this is less of a burden than writing something that goes from the "glorious language" into machine code. Understanding why that is less of a burden is gained by writing a compiler where you go right from "expressing what you want" to "machine code that does that".
- dzaima 5y agoI mean, a C interface is better than a machine code interface. The problem with that is that, unless you include a C compiler (or at least a thing that understands the 176 C ABIs) with your language, you can't use it. (not that machine code would be better at that, but I'm sure that if people actually intentionally attempted to make a global cross-platform ABI, they'd easily make something much better than C)
- Koshkin 5y ago> a C interface is better than a machine code interface The last thing I want when I write code in assembly is to have to call a C library just to invoke a system function.
- dzaima 5y agoYou'd obviously prefer calling into things made in your own language than some other. But, from any other language you'd much prefer a C interface over having to explicitly describe which registers & stack slots to put things in and read from.
- mcronce 5y agoI did this once trying to mitigate Go's FFI performance cost. It wasn't great but it wasn't awful either. If I had to do it again I'd generate the assembly trampolines.
- robocat 5y ago> Go's FFI performance cost https://news.ycombinator.com/item?id=17165179 https://news.ycombinator.com/item?id=17165179
- mcronce 5y agoThere are a couple solid summaries in that thread based on my experience going through that exercise - thanks for the link In case anybody wants to go down the rabbit hole of shit you should definitely not use in production (but we did anyway), this was my starting point: https://words.filippo.io/rustgo/ https://words.filippo.io/rustgo/ I did not, however, `no_std` or avoid heap allocation on the Rust side. Everything worked great, including running a multithreaded tokio runtime. Still do not recommend in prod ;)
- lmm 5y ago> My position is that this is less of a burden than writing something that goes from the "glorious language" into machine code. I disagree. Machine code has a small stable surface area. Compiling to a bootable image for a single-tasking machine is easier than compiling to a well-behaved userspace unix program that operates the way users expect.
- aidenn0 5y ago> My position is that this is less of a burden than writing something that goes from the "glorious language" into machine code. It's only less of a burden if you're guaranteed to have a C compiler hanging around any time the C ABI breaks. If you aren't guaranteed to have a C compiler hanging around any time the C ABI breaks, then you are probably just as well off generating C-ABI compatible machine code from an ABI description written in "glorious language" and updating it when the C ABI breaks. Non self-hosting languages distributed as source code can just lean on the C compiler for everything. It's also quite feasible to target Linux without worrying about the C ABI, as the Linux system call interface is famously stable, but that is not true of any BSD.
- PaulDavisThe1st 5y ago> but more that literally every single interface to literally anything is either written in C, or isn't meant to be used by multiple languages. C is the de facto standard for interacting with anything not written in your language. Even that is not the real complaint, since the alternative to this (N different FFI-style APIs) is madness. The heart of the complaint is "great, we have effectively a single interface to almost everything, which is probably a good idea, except that the interface sucks".
- pdonis 5y ago> C is the de facto standard for interacting with anything not written in your language. Not necessarily. C is how your language interacts with the OS if you use the OS's C library. But not all languages do. Go doesn't. The only thing you have to do to interact with the OS is make system calls. You can do that without going through the C library. It might be a PITA to do it if you're not working on Go for Google, but if that's the real problem, that's what the author of this article should have complained about. (It's actually less of a PITA on Linux because the syscall interface is implemented using software interrupts. Windows is more of a PITA because the OS goes out of its way to make its syscall interface look like a C interface.)
- dzaima 5y agoAgain, there's more than the OS kernel that a programming language will need to interact with. You don't go through syscalls to make an X11 window or read keyboard/mouse inputs or draw graphics. There are thousands of utilities that are meant to be usable cross-language, but in actuality use the C ABI (well, at least one of the 176 C ABIs there are).
- yjftsjthsd-h 5y ago> C is how your language interacts with the OS if you use the OS's C library. But not all languages do. Go doesn't. ...on Linux. Pretty much everywhere else, libc is the way to interact with the kernel; even Go goes through libc on ex. Darwin and OpenBSD, because Linux presenting a stable kernel ABI is actually pretty unusual.
- titzer 5y ago> Linux presenting a stable kernel ABI is actually pretty unusual. Did you mean "portable"? Because the ABI to the Linux kernel system calls is very stable. Literally the 32-bit syscall interface has not changed (except by addition) in 30 years. The darwin kernel is also pretty stable, except Apple moves so fast from one architecture to the next that they drop support for old ISAs pretty fast. I predict they'll drop support for x86 altogether in ~5 years.
- legalcorrection 5y agoYou should think of C as a front-end for the computing platform you are targeting. The platform has an ABI, which you need to use to interact with the system components. So because every third-party has to speak that ABI to interface with the platform, they might as well use that ABI to interface with each other too. You can of course build your own little world within a platform, with all your binaries speaking a different ABI to each other. And that might have some advantages, but most people find those advantages outweighed by just using the same ABI as the platform.
- rayiner 5y ago> Window management, I/O, graphics, everything has a C interface. You say that like it's a bad thing. The situation has gotten much worse for third-party languages these days, with frameworks being written Javascript, Swift, etc., which are hard to bind to without fundamental impacts on your language design.
- dzaima 5y agoYes, it is possible to make worse ABIs than C's. That's not a surprise. Doesn't mean C's is automagically the best possible. Something that, at the very least, doesn't have varying sizes for the same type between architectures/OSes, and precisely defines structure layout/padding, would be vastly better. (not saying that's a realistic thing to get at this point, but doesn't change the fact that it'd be much nicer.)
- rayiner 5y agoI’m not saying it’s the best thing, but I’m not sure you can get much better. A lot of things defined by the C ABI are things you’d have to do anyway if you’re compiling to native code (structure alignment, where’s the stack, what’s called-save, callee-save, where do you find the return value, etc.) Targeting the C ABI’s set of choices isn’t that different from targeting a different set of choices. And there are gratuitous differences in C ABIs, for sure. But often there’s good reasons. X86 had no register arguments because few registers; same reason it had no thread pointer. RISC architectures had weird limitations on unaligned access, etc. affecting struct layout. Maybe I’m being dense. What does a good alternative look like? CORBA?
- dzaima 5y agoBetween architectures you'd indeed need quite a few differences, but for the same architecture it'd be nice if things more or less agreed on things. Specifically, I think it'd be very reasonable & possible to have an ABI that has various floats & integers (specified width of course), and pointers & structures, that has consistent conservative padding on all architectures and precisely one way any given structure is laid out in memory (ok, maybe two, with LSB & MSB integers; but I think that's literally all the variation there is (and MSB is nearly dead too)). Not the most efficient thing on all architectures, but for language inter-communication it shouldn't be too bad to lose a couple nanoseconds here and there, and I'd guess it'd outweigh the alternative of needing more generic (and thus, less optimized) code handling each individually.
- _3u10 5y agoWhere is the C interface to Symbolics Lisp machines…? There’s lots of alternatives, MSR wrote an OS in C#
- dzaima 5y agoA lisp machine, by definition, runs lisp. The ABI problem only exists in environments where multiple programming languages exist. I doubt much non-.NET software runs on that C# OS either. If you want multiple programming languages to be able to sanely run within a single OS (and do more than just pure computation), though, you have the ABI problem, and this is what the whole discussion is about.
- fiddlerwoaroof 5y agoThe Symbolics lisp machines had C and Fortran compilers
- pjmlp 5y agoImplemented in Lisp.
- pjmlp 5y ago.NET was created as a Common Language Runtime. When it was announced it supported about 27 languages. From Microsoft themselves, J#, C#, VB.NET, and Managed C++ (later replaced by C++/CLI). It was WebAssembly before its time (among many others), with tons of features that WebAssembly is yet to support.
- aidenn0 5y agoGenera definitely had a C (and I think C++) interface.
- pjmlp 5y agoWritten on top of Lisp.
- Rury 5y agoI think that's besides his point, which I take is: Replace C with an alternative and people will complain of similar problems, since all abstractions are leaky abstractions to some extent. Or in other words, since you can never be immune to this "leaky" problem, you will inevitably have similar kinds of problems despite using an alternative. Which is why you'll find every programming language has critics. Also, keep in mind having alternatives isn't necessarily better, as it introduces a problem itself: it complicates things (the article even mentions a problem of this sort). Does having 100 programming languages, with dozens of OS's, each all doing mostly the same sort of things in different ways - simple? Might the programming world be simpler if there was 1 programming language/OS/way of doing something, rather than having 100s of alternatives? (This is just food for thought to demonstrate the point, not something I'm particularly advocating)