Hacker News new | ask | show | jobs
by spoiler 3370 days ago
> These “you should switch language” remarks are strangely enough from the backseat drivers of the Internet. Those who can tell us with confidence how to run our project but who don’t actually show us any code.

This is an usual problem with people participating in discussion over the Internet. I am sure those people mean well, but often they don't put enough effort into assessing the situation and underestimate its complexity before they decide to hit the keyboard. I've myself done it a number of times, but I am working on not doing it.

Advice for the people who are making all these suggestions and: A good way to see if you're talking out of your ass—unintentionally, of course—is to try to do what you're saying someone should do. Just try and re-write some parts of curl in Rust (you can go with a hip name like rurl). It's a good exercise to learn about the project you're rewriting, the language you're writing it in, and the problem domain. So, at the very least you'll get something out of it, and if your project is successful: even better!

12 comments

Hear hear! At Recurse Center this is an explicit (lightweight) social rule:

NO BACK-SEAT DRIVING. If you overhear people working through a problem, you shouldn't intermittently lob advice across the room. This can lead to the "too many cooks" problem, but more important, it can be rude and disruptive to half-participate in a conversation. This isn't to say you shouldn't help, offer advice, or join conversations. On the contrary, we encourage all those things. Rather, it just means that when you want to help out or work with others, you should fully engage and not just butt in sporadically.

From https://www.recurse.com/manual#sub-sec-social-rules

It is unfortunate that these things have to be pointed out, but they do.
Ironically you are violating another recurse center social rule in saying this: no feigning surprise, i.e. just because something is obvious to you doesn't mean it is obvious to anyone else, so don't act surprised when someone doesn't know or understand something.
Touché! - the surprise on my part is genuine, though maybe it should not have been.
Why? This is a particularly hard lesson to learn and everybody has to learn it, why not write it down in places?
Because everyone has had their own experience that they have learned from. Most people who do this are not trying to be a troll. They really have learned A lesson and want to help you by sharing. The problem is few people have the context to know all the important issues, they just know they were burned badly one time and want to save you not realizing that the solution they found has downsides that will burn the other guy.
Its even more obtuse whey back seat drivers exclaim, we should try and stop you from doing that! Its unsafe!
Were do I send proposals for "comment of the month"?

More seriously speaking: IMO this is solid advice. It

- is actionable

- goes out of its way to be polite and respectful

- has a chance to actually improve online discussions one comment (and hopefully commit) at a time

"For every complex problem there is an answer that is clear, simple, and wrong."
And you're own comment is delightfully self referential (or not) - so both of you have up-votes for being so reasonable! :-)
I think that you express a fallacy. You're saying that nobody can provide thoughtful criticism unless they take up the task themselves. So the next time you criticize politics, are you going to run for office? The next time you criticize a meal, are you going to become a chef? The next time you criticize a car, are you going to become an engineer? Yes, it's one thing to make thoughtless and uninformed criticism. But providing thoughtful and useful criticism does not necessarily require actively creating something from scratch. Otherwise, we would all only be starting new projects and never collaborating!
No, he's spot on. The one thing that keeps happening over-and-over again is that people who have never put together a system of any complexity will yell from the sidelines how others should build their stuff.

This goes for operating systems, application software and advanced rocketry alike.

The reason we have so much C code powering the world is that (1) there wasn't anything better when that code was written, (2) time has weeded out most of the bad bugs to the point that the old codebase will be substantially more stable than anything new no matter what language you would write it in.

If someone is willing to throw a few hundred million or so at re-building an operating system from the ground up that is 100% safe and reliable and that does not have more bugs than what is available right now then they are free to do so. They're also free to donate their own time and to try to enlist their buddies. But they're not free to yell at others how those others should do their jobs.

Show don't tell.

> If someone is willing to throw a few hundred million or so at re-building an operating system from the ground up that is 100% safe and reliable and that does not have more bugs than what is available right now then they are free to do so.

But at the same time - we are spending those billions. We keep throwing billions at Apple by buying their new phones, yet they release lists of security issues which this time were basically all:

  - malicious crafted image -> remote code execution

  - maliciously crafted font -> remote code execution

  - maliciously crafted audio -> remote code execution
I'm not sure if I have to be able to write a font parser and rendering subsystem in a memory safe language myself to be allowed to complain that Apple is using my money for something other than doing just that. To me it's completely mind blowing that someone uses a C library to parse complex third party binary data from the internet.
If c lib is mind-blowing, what about kernel and it's extensions?

For now c is the only thing we have that can be used so widely. Some day we may be able to use rust or something else, but that's future, not present.

Any lang that easily calls C and can be called by C, or can be compiled to C should be fine to use today.

Re: kernel - it's a lot of pretty simple subsystems. Each system is usually simpler (easier to verify and polish) than a lot of common libs doing really complex things (ssl, video codecs, ttf, ...). Complexity + raw pointers quickly add up to guaranteed problems.

Rust uses llvm. Use it for new development on any platform that llvm supports. A few microcontrollers might be left out.

Rust can speak C's ABI, so you can write kernel extensions in Rust. There's some legwork involved, but it's quite possible.
Interesting.

So you're saying that Rust, at the moment, in theory, can be used in any place where C is required? Ie. writing kext on macOS, loadable kernel module on Linux or things like extension for SQLite are all possible?

In that case I wonder if there are any theoretical blockers for things like (using no_std and) mapping internally used C structures (let's say BSD kernel's rbtree) into typed, first-class Rust citizens - to avoid std overhead and reuse what's already available? In other words - is there anything there in C macros that can't effectively be expressed in Rust for example?

>The reason we have so much C code powering the world is that (1) there wasn't anything better when that code was written...

Right, but the criticism he received for his first post was not primarily about choosing the wrong language or about refusing to rewrite in a different language now. It was primarily about downplaying the role of C in the security issues that were found.

The rest of the debate, at least as I read it, was not so much criticism as it was a generic debate about the pros and cons of various programming languages like we're having one every other day on here and on reddit.

Choosing C back then was clearly justified for a project like curl given all the constraints and considerations. And for a rewrite to be a net positive in terms of security probably takes years, not to mention the huge effort that someone would have to put into it.

I have put together systems of considerable complexity (>100k lines), and am working professional programmer for almost 2 decades. Most of my work does not involve C, but various "safe" languages.

There were better alternatives already available at the beginning of the 70s, and certainly when most of the software was written that we are using today. Just to name a few I am familiar of with:

- Pascal being as old as C, and later on

- Modula 2, Oberon, the Oberon System was completely implemented in Oberon

- Eiffel

and of course, today:

- Rust

- Go

So, even back then, there were more safe alternatives to C around. C gained more popularity, and consequently the tooling gave it some edge, but there would have been alternatives. Of course, when you have a nice debugged C program, that is something worth keeping. And as a consequence, for mostly historic reasons, a lot of our current infrastructure is built on top of C - but that alone does not mean that C was the perfect or even the right tool to build all of this upon.

> (2) time has weeded out most of the bad bugs to the point that the old codebase will be substantially more stable than anything new no matter what language you would write it in.

This seems to assume that the codebase is stable and in maintainance mode. However, the reality for the vast majority of open-source projects is that they're either being actively developed, adding new code and new bugs, or they're abandoned.

I wouldn't put it as strongly--I think valid criticism can come from someone who hasn't "put something together"--but at the same time I think a lot of the criticism in this area isn't all that valid. Some of it is, but mostly it seems to me just people parroting "c is unsafe" as though that is itself the end of the discussion.
Exactly, show don't tell. And when I point to the fact that the Rust codebase itself has a lot of "unsafe" places I get the explanation "yes, but it's an old code and we haven't had the time to rewrite it to use the newer features that would allow more safe code."

Think about it: the people who design Rust don't have the time to rewrite their own Rust code to be safe.

When there's no time to rewrite the code of Rust to be demonstrably safe, why should any other project have more time than that, where the programmers know Rust much less or not at all?

Maintaining the successful project is hard and takes a lot of time, even without switching to something new.

Second point: look at the Benchmark game, a fast Rust code example also typically has an "unsafe" code. So it's still not even demonstrated that "you can have it both fast and safe" holds for these examples. Fast as in "as fast as C" and "safe" as in "provably safer than C."

Finally, I believe that the language should simply implement a language-level no-cost check for integer overflow, as the machine languages already have, and not complain that there aren't some special mechanisms in CPUs to do it differently. It's your language's failure if you can't use what already exists. The CPUs already can do it, the high level languages don't provide the high-level access to it. Which doesn't matter for C which is "unsafe" by definition (and where it's natural to call some asm when needed) but it should for Rust which goal is to produce a more provably "safe" code.

Writing unsafe Rust instead of unsafe C is not giving you any real advantage for the existing projects, as long as the state is as it is.

Also, look how Rust uses TLS. Is safely rewriting a crypto library which is useful in real project still a too big task to be taken?

I like the perspectives of what Rust could bring. But I'd like to see a real life case of its success too.

> Writing unsafe Rust instead of unsafe C is not giving you any real advantage for the existing projects, as long as the state is as it is.

Your argument hinges pretty heavily on this. It's incorrect. The reality is that unsafe code in rust is not like unsafe code in C. First, it's bounded to a module. Second, you can grep for it (huge). Third, you still have less UB in unsafe rust than in C.

I've never written code in rust that required unsafe, after many thousands of lines.

> Is safely rewriting a crypto library which is useful in real project still a too big task to be taken?

https://github.com/ctz/rustls

?????????????

> But I'd like to see a real life case of its success too.

Ripgrep is a nice one to point to. There's redox too. Tons of rust code out there.

> It's incorrect.

> I've never written code in rust that required unsafe, after many thousands of lines.

That illustrates the level of understanding of those who argue that curl should be rewritten in rust. Bravo.

Why, specifically?
> when I point to the fact that the Rust codebase itself has a lot of "unsafe" places

One of the criteria for being in the standard library is "is this something which needs a lot of unsafe." This is so it can receive extra auditing, etc.

> yes, but it's an old code

This may have been true a while ago, but in my understanding (I'm not on the library team) it isn't really any more.

> why should any other project have more time than that

Because they do not need to write their own unsafe code, since it's already done in the standard library.

Generally speaking, applications in Rust should almost never need unsafe. Libraries may.

> a fast Rust code example also typically has an "unsafe" code.

This is not really true anymore; in fact, recently some programs were contributed that are 100% safe yet are faster than their previous, unsafe-using versions.

> believe that the language should simply implement a language-level no-cost check for integer overflow

This is not viable. Not enough machines have this.

> Writing unsafe Rust instead of unsafe C is not giving you any real advantage for the existing projects, as long as the state is as it is.

Unsafe Rust still has many, many more safety checks than C.

> Also, look how Rust uses TLS. Is safely rewriting a crypto library which is useful in real project still a too big task to be taken?

https://crates.io/crates/ring ?

> This is not viable. Not enough machines have this.

Of course they have. It's a basic set of machine code instructions. Can you specify which doesn't please?

> One of the criteria for being in the standard library is "is this something which needs a lot of unsafe."

Do you honestly think a project like curl has everything it needs "which needs a lot of unsafe" already implemented in the current standard libraries?

Why don't you rewrite the curl in Rust then, it's just using what's already written? Let me know how far you come.

> https://crates.io/crates/ring ?

Does it have all the features that curl needs, or does curl still have to use a Rust wrapper around openssl, inheriting all the potential unsafety problems of openssl anyway? What is worth then, in percentage, having anyway less exposed part of the code in Rust? How many other wrappers curl has to use? Have you tried to check and estimate if it's still worth?

Once again, Rust people should first demonstrate that they can manage to make any relevant library "cleanly" safe, then complete the feature set, and only then expect big non-trivial programs consider using some Rust.

First make the basics safe, then let us use that basics. Once you have save openssl equivalent, even C programs can link to it and be much less exposed to the potential problems than they are now. It's that direction that only has sense.

> Of course they have. It's a basic set of machine code instructions. Can you specify which doesn't please?

That they exist is not the problem. That they exist _and_ don't provide enough performance is the issue. That is, your "no cost" is what I'm asserting here, not that it doesn't exist at all.

(This is not my area of specialty but was brought up when discussing this behavior; it's measured as a 20%-100% hit to speed, which is unacceptable.)

> Do you honestly think a project like curl has everything it needs "which needs a lot of unsafe" already implemented in the current standard libraries?

I don't think a project like curl needs much (if any) unsafe.

> Why don't you rewrite the curl in Rust then, it's just using what's already written? Let me know how far you come.

I did not suggest that curl should be re-written in Rust. I do think a functional equivalent in Rust would be good to have. I do not have the time to write such a thing myself. Luckily, many others have been working on this kind of thing.

> does curl still have to use a Rust wrapper around openssl,

ring is a port of BoringSSL to Rust, piecemeal. It still has some C code today, but at the end, will be all Rust/asm. Given that BoringSSL is a fork of OpenSSL, I would imagine that it would have enough functionality.

> Second point: look at the Benchmark game, a fast Rust code example also typically has an "unsafe" code.

That's false. From[1], it looks like two submissions use `unsafe`. And one of those is for ffi to gmp.

[1] - http://benchmarksgame.alioth.debian.org/u64q/rust.html

OK. I only looked at the programs linked directly from: http://benchmarksgame.alioth.debian.org/u64q/rust.html
I think it's missing the point to count the programs that aren't the fastest, i.e. only one each of the spectral-norms and pi-digits are "interesting".
> Benchmark game, a fast Rust code example also typically has an "unsafe" code

So you say but do not show.

Please show us which of those Rust programs you count as "fast".

Please show us how many of those programs have unsafe code.

It's not what I tried to say, but I see your point. I merely pointed out that the people who're saying saying "Why not rewrite curl in X" probably didn't stop to think how challenging it would be.

> The next time you criticize a meal, are you going to become a chef?

Well, they're not criticising the meal here, they're criticising the kitchen it was prepared in. :P

But joking aside, they don't need to rebuild all of curl in <language of choice>, just get it started, and if enough people think it's a worthwhile project, they will contribute.

> But providing thoughtful and useful criticism does not necessarily require actively creating something from scratch.

I agree. However, a lot of these comments are along the lines of "C is unsafe. Go rewrite curl in Rust!"[1] without realising how much effort and time that would take (and I'd not be surprised if some portion of this group never worked on a project in either language). I personally don't find those types of comments very useful.

> Otherwise, we would all only be starting new projects and never collaborating!

This is what the people I'm referring to are essentially asking. Going hybrid would probably introduce subtle bugs, and increase complexity and maintainability down the line.

[1]: I love Rust, and a few of my recent pet projects are being written in Rust (one of which is being ported from C). So, I'm not trying to bash Rust. I'd even encourage anyone to use Rust over C, if they were to start a new project.

It's one thing to criticize somebody over a missing feature or a bug. It doesn't take an engineer to author a valid complaint when a car door handle falls off. It's another thing entirely to criticize an entire methodology or to try to dictate exactly how something should be done.
I don't think this generalises that well. We're learning some general truths that should be known to many people with enough time. You can certainly criticise whole architecture and methodology based on those ideas. For some ideas it took a long time before they became something obvious - we may be at a time when the scales are slowly tipping.

For example imagine telling someone in 2000 that they should be running an automated continuous integration pipeline rather than purely manual testing. Now it's a norm. Then, we were still discussing whether Extreme Programming was a waste of time. But we also didn't have the tools to support the CI properly.

Memory safe compiled languages seem to me like the same thing. We had things like Cyclone, OOC, and other experiments which barely anyone knew. Now we have Rust which is still hard to use, but it's gaining ground. In a decade, I hope to be pointing out to this post when someone complains that you can't criticize an entire methodology. "Remember when people said the same thing about enforced memory safety?"

Curl will not be rewritten of course. But I'm happy people push this idea. The next curl will not be written in C.

> It doesn't take an engineer to author a valid complaint when a car door handle falls off. It's another thing entirely to criticize an entire methodology or to try to dictate exactly how something should be done.

But if a car manufacturer consistently uses a production methodology which causes door handles to keep falling off, again and again, even after they've been re-glued on for the Nth time...

Then I think it's fair game to say that you think there's something wrong with the methodology. People suggesting alternate approaches without putting in the actual work involved may very well be "backseat drivers of the Internet"-type commenters, but that doesn't mean they're not on to something.

If my comment could be construed in any way as an attack on people for suggesting others use different languages such as Rust, it was not intended. I'm a fan of Rust myself and I would recommend it to anyone who wants to start a new project.

My comment was meant to pertain to the suggestion floating around that Daniel ought to undertake a total rewrite of curl in Rust. That's an entirely different ball of wax. It's like telling the car maker to tear down and build a new factory because the door handles keep falling off.

>But if a car manufacturer consistently uses a production methodology which causes door handles to keep falling off, again and again, even after they've been re-glued on for the Nth time...

We know the characteristics of glue, and have switched to better glues. All our assembly jigs work with glue. When the handle falls off it is easy and cheap to glue it back on.

If we switch to screws we need to redesign the parts and the jigs; and reorder the entry assembly line. [Not realized by the engineers at the time is if they use screws dissimilar metals of the screws corrode and result in the handle falling off as well - and it is a much more expensive fix because you have to replace the handle and the part it attaches to as both have nothing to screw into)

If I say: "There are all these bugs in curl, you should rewrite it in rust and it will be better (but I've never done anything similar, nor there is any scienetific proof for what I am saying)" then it's not thoughtful criticism, but pure personal opinion. There is a very low value in that.

On the other hand if there is a project like curl rewritten from C to Rust and its author says: "We have switched from C to Rust in a year and after two years we have less new bugs", there is at least some value.

I think the parent is correct, and the situation is more nuanced than your argument would suggest.

Politics: Are you critiquing the distribution of funds to the school your child attends? You probably have some insight there. Are you instead expressing a strong opinion on a complex subject that you likely don't have an iota of experience with? Well, then you should realize that you're probably not in a position to have such a strong opinion.

Meal: You're the user, so you have experience here. All you're commenting on is how it tastes to you, so that's perfectly valid, no need to become a chef.

Car: Again, you're the user. Are you critiquing a UX problem? Well, then you're in a perfect position to do so. If you're remarking about e.g. the torque to weight ratio then you should probably understand some of the engineering that goes into creating a vehicle.

Your argument is the fallacious one here. You're making an all or nothing comparison and life rarely works that way. If you're going to make a statement like "you should rewrite curl in X language" then yes, you should know what the hell you're talking about because you're making an engineering level statement.

I wasn't making the argument that curl should be rewritten in Rust. It's too late to edit my comment to clarify it, so please see my response here: https://news.ycombinator.com/item?id=13996154
It's not that anyone who has an opinion or criticism has to be an expert or be in the trenches. But in the same token not every tom, dick and harry has valuable opinion or criticism that puts them on par with people doing the work or legitimate experts. There's certainly a fine line to walk between ignoring people or wasting your time trying to filter out a cacophony of opinion and belief from anyone willing to utter it.
No, it is not a fallacy - when it comes to matters of opinion on the feasibility of difficult tasks, experience has some relevance.

Your objection follows a common pattern - if we took every nuanced situation and turned it into a universal black-and-white dichotomy, we would end up with half the arguments on the internet.

God help anyone criticizing Google. You make your own multi billion corporation.
If a person was claiming it should be much bigger and more successful than it is, and that claim is primarily opinion-based, one might take into consideration that person's achievements when evaluating their claim.
Replying to myself, since I can no longer edit what I posted: I'm not advocating the developers of curl rewriting it in Rust! I think that a lot of the debate here is around a few different points, and that we're generally talking past one another. My primary concern was that the initial response seemed to disregard the vulnerabilities that can occur due to unsafe memory management. To the extent that I read people say arguments along the line of "you can only make that criticism if you write a curl replacement yourself", I felt that that was unfair.
D is compatible enough with C/C++ that I have been able to take largish multifile projects and convert them one file at a time to D. The full regression suite was run after each file was converted. This helped ensure both an accurate conversion and did not leave the project in a broken state for an extended period.
I've successfully converted many projects from one language to another using this method. One was a huge assembler program I converted to C back in the 1980s (ironically, so it could be ported to other platforms!).
> Just try and re-write some parts of curl in Rust

I don't doubt that some suggestions have come from backseat drivers... but I also don't believe that's relevant. First, people are implementing curl's functionality in Rust (e.g. hyper, reqwest) and it's working out well. Second, you don't have to be the one implementing something to push for improvements- in the general case, that's absurd.

> ... people are implementing curl's functionality in Rust (e.g. hyper, reqwest) and it's working out well

That is good, and it's the reasonable thing to do. New tools provide the same functionality, get used where curl would have been used otherwise, and when the time is right, curl can enjoy a well-earned retirement in the hall of fame of famous ancient projects.

There is a certain type of person (I once fit the mold) who thinks new languages could significantly improve software development. The evidence is to the contrary, and many improvements turn out to be double-edged swords, capable of doing damage in the wrong hands. I am still interested in new languages, but I am no longer looking for the holy grail.
I've actually grown extremely bored of programming language debates and yet continue to be fascinated with the act of programming. Each language has something new to offer and also some limitation(s). Why not try them all?

I believe opening our minds will be the only way to achieve meaningful improvement in software development.

I also believe this is easier said than done.

You only get these kind of advices, not when you need them, but when your project is successful ... Everyone want to help a successful project. But while struggling, you get very little help.
Bang on point. All the people who complain "oh but C is so dangerous you should rewrite in $HotNewLanguage" do nothing to actually help with their "expert" recommendation.
I used to program in $BoringOldTurboPascal, before C became the $HotNewLanguage in systems programming, so excuse me if I feel like I know one thing or two about C security exploits.
Isn't C 11 years older than Turbo Pascal?
C was a UNIX only language, it had no relevance outside UNIX in the 80's.

Those of us using CP/M and other systems had access to K&R C dialects like Small C, not fully compatible with C.

In those days C was just another systems programming language, looking for a spotlight.

That spotlight came thanks to universities adoption of UNIX, which given AT&T prohibition to profit from it, it was sold at symbolic prices and a few AT&T researchers did provide tapes to universities. Which then started to adopt UNIX instead of paying commercial licenses for other OSes.

So when workstation startups like Sun and SGI started to look for OSes, they based their software stack on UNIX.

Before the widespread of UNIX out of university labs into the workstation market, C wasn't that relevant.

You see the same happening nowadays with Browser == UNIX and JavaScript == C.

Also C is actually 10 years younger than Algol or PL/I, both used to implement several mainframe OSes.

I disagree that C was looking for spotlight.

C was the system programming language of Unix. Many people wanted Unix, so they started programming in C, because that was the best supported language. In the late 70s, byte code interpreted Pascal was also popular on Unix because it allowed for bigger programs on the then current 16-bit systems.

It's pity that Modula-3 never got much traction. I guess that's part do to Modula's overly verbose syntax.

C works as long as the platform is sufficiently like Unix.

For example, in the MS-DOS world with near and far pointers, programming in C becomes utterly confusing.

These days, linker scripts and ELF hide a lot of stuff C cannot express.

> For example, in the MS-DOS world with near and far pointers, programming in C becomes utterly confusing.

C can still be really "interesting" on Harvard architectures (many popular micros, PIC and AVR for example). Though it isn't that bad, since the compiler sorts constants and the like automatically out and loads them into memory (which means that by default constants that are not optimized out - like strings - will be deduced from the available memory ... 64 to 2048 bytes on typical SKUs).

For any sizable project in the public, I think switching languages is never the right choice. That is at best confusing for people, and at worst kills the project. The right way to replace a library or application is to build something better. If it matters, possibly with the same, or a close enough API.

This is the only thing I've seen work in the past.

Yup, I wanted to comment on the very same thing, but you did it better. Thumbs up.
I suggested cRUST as name
I would also like to see these arm chair developers bootstrap a new set of compilers, operating system and tool chain with a native system interface written entirely in there super cool new languages that are going to replace C and C++.

For all the talk of 'a better system programming language' and replacing C/C++ there is curiously little interest or code written to prove that any of these new languages can be used to write systems from scratch and that the language and runtime can scale across architectures.

Thats before you even get to a comparison of efficacy and speed vs C/C++.

The problem is catching up with 40 years of history.

The quality of code generated by C compilers used to be pretty lame in the 80's, any junior Assembly programmer could do better.

As for ubiquity, C was a UNIX only language, with K&R C incomplete dialects available in other systems, where C was just "yet another language".

It was the adoption of UNIX, an almost free ($$) with source code available, by the 80's startups for creating the workstation market (like Sun and SGI) that lead to UNIX and C's adoption in the market.

Had UNIX been as expensive to get as the other OS of the time, and we wouldn't be talking about C's ubiquity and execution speed of generated code.

How much history can you try to rewrite in one comment?

A vast amount of software in C was written for other platforms than UNIX, both SGI and SUN were companies that were focused on selling hardware rather than software. If anything the workstation market was created by companies like Xerox and commercialized by companies like Apollo.

UNIX was for a long time a very expensive operating system on X86, it only became affordable with SCO/Xenix and it became free with 386BSD by Bill and Lynne Jolitz and later Linux by Linus Torvalds.

C definitely wasn't a UNIX only language, it was available for an enormous range of computers from 8 bitters to top of the line machines. In fact that (and not UNIX) was a major factor in C's long time dominance.

None, as I was there.

Companies buying UNIX weren't buying X86 systems to run it.

We were using CP/M (on Spectrum +3 A), MS-DOS, Atari, Amiga, C64, ZX Spectrum, MSX.

C was just yet another programming language, nothing special about it.

In fact the only reason to bother having a C compiler on those systems for my group of acquaintances, was to be able to bring home the work done in expensive UNIX computers at school.

C supporters are the ones that like to rewrite history by selling UNIX and C as if they were the genesis of systems programming and OSes.

Well when I started programming Windows 3.1 it was with Microsoft C 7 and the help of the Petzold book. At that time it seemed to be the main way of writing Windows programs, at least until Visual Basic 3 came out anyway. It wasn't just another programming language in the Windows world. It was the programming language.
I was using Turbo Pascal for Windows 1.5 and Borland C++ 3.1 instead.

Also by the time Windows 3.1 got out MS-DOS was already at version MS-DOS 5.0 and DR-DOS at version 6.0.

During the lifetime of MS-DOS, many of us were happily coding on Clipper, Dbase, Turbo Pascal, Turbo Basic, Quick Pascal, TMT Pascal, FoxPro, NASM, TASM, Turbo C, Turbo C++, Modula-2....

There was plenty of choice.

You are looking at the 1990s, not the 1970s and early 1980s when this was taking place. By the late 1980s Microsoft realized they needed a higher level language and C was already winning by then. Microsoft just helped push it along.
I think you're not looking hard enough. There's lots of operating systems being written in the weirdest languages. So are the toolchains and compilers. People do it for fun - just look at osdev forums. It's not a new thing either, I was doing some development on an AOT CIL compiled, single memory segment system a decade ago. Kind of like Singularity.

But it takes time. Unless you're actually looking for those projects, don't expect to even know they exist during the first 5 years.