Threads for munksgaard

      1. 13

        10 years feels like an absurdly short period for a consumer device that doesn’t see much wear and tear, Google really dropped the ball there. At least there’s a way to invoke a debug menu and bypass the auth step as a temporary solution.

        1. 8

          Yeah, disabling the certificate check through Activity Manager worked for me, but this is pretty embarrassing for Google.

        2. 20

          Perhaps a direct link to the LKLM thread would be more interesting? There are comments from many other maintainers, including Christoph Hellwig who recently was part of some drama.

          1. 26

            Ron, Peter, and Joe all arrive at Rivendell and Elrond gives them a task, “I must get a message to Thranduil in Mirkwood, surely you all know the way, please each take a copy and travel separately to avoid Orcs.”

            Peter, an Elf not much younger than Elrond, has been there many times, and truth told Elrond is pretty sure Peter will get there before everyone, and the others would be unnecessary, but it is very important and Glorfindel insisted. He leaves in the morning, and arrives at Thranduil’s court a few days later.

            Ron, a stout, but not particularly well-travelled Hobbit, takes the message and his charge and proceeds to leave Rivendell with nothing more than good cheer and an understanding that his destination is somewhere in those woods over there. He wanders for four days, then returns to Rivendell for several years to recover from his adventure before going back out and probably following someone else’s path just a bit. He does, however, manage to learn the exact species of every tree in a five mile radius of Rivendell. Thranduil is impressed, if annoyed at the lateness of the arrival.

            Joe, a Ranger from the ruins of Arnor, takes the message. He also doesn’t know the way, and for the first couple days he just wanders around with Ron, learning the lay of the land, which side of the tree the moss grows on, all that. He realizes after a bit of observation that there is a subtle Elf-way through the woods, something that Peter definitely understood, but that Ron was a little too focused on exploring the scenery to notice. He studies the ways carefully, and eventually picks up on how to follow them, he arrives at Thranduil’s court only a few days after Peter.

            Who’s journey through the woods is best?

            Peter certainly got there faster, but did he learn anything about Mirkwood on the way? I suppose he didn’t need to, being an ancient and wise Elf.

            Ron took forever to arrive, but when he got there he was able to teach the Elves a couple of, admittedly not super valuable, but interesting things. Thranduil also noted that – if they ever needed someone to map out the ruins of Old Beleriand, which not even the Elves remember, Ron might be their guy.

            Joe split the difference, learning about the Thranduil’s Demense, discovering the secret paths, and arriving in a timely manner. He, too, came with some interesting new knowledge from his journey, whether it is useful is likely for the future to decide, but he is already teaching the others about both the trees and the elf-ways.

            The point of this parable is to take issue with the conclusion of the OP:

            This doesn’t happen by accident. The developer needs to hold the entire structure in their head, and find a simple path that connects its constituent parts. And if no such path can be found, they need to find a better structure.

            This is, in my experience, not possible for any reasonable sized ‘real’ problem. Not even the Elves know every path through Mirkwood; but you can often recover the necessary information if you don’t mind wandering around a bit. Sure, be cautious not to overdo it, but don’t forget that you might be an Elf solving and Elvish task, when everyone else is an easily distractible Hobbit who’s never seen this kind of tree before. I don’t think we should try to be Peter or Ron, here, they are different in the same way that Depth-first and Breadth-first search are different. Peter had prior understanding and knowledge of the problem space, Ron did not. The problem is also pretty simple and well-understood, the fact that Ron did not avail himself of other’s work isn’t particularly realistic, but then again, this is fodder for blog-posts, no mission-critical customer-facing software; maybe that was the point.

            IME, it pays to be like Joe (that’s why I named him after me – also vanity), incremental approaches are valuable to build up domain knowledge, maybe even starting on a design, while also regularly looking for better joints at which to carve nature into it’s natural constituent parts. In every real problem I’ve encountered, I’ve never been able to fully hold the whole problemspace in my head, and have to rely on general knowledge gathered by idle exploration and trail maintenance. I don’t so much hold a structure as a metastructure a set of invariants and practices and techniques used by me and all my fellow trailmakers. I don’t need to hold the whole structure of a subsystem because I know the folks maintaining it follow our practices and maintain invariants – I don’t need to know every Elf-way and where it goes, only the ones I need to.

            I guess my point is – I don’t think anything has to be any one way, and there is merit in all three approaches, my question at the end of my self-indulgent parable is a false choice, the correct answer is ‘None of the above, they all got to their intended destination, even if Ron had never arrived at Thranduil’s court, he would’ve still arrived precisely where he meant to.’

            PS: Please also don’t take this to be an indictment of the very good article.

            1. 10

              Hi, author here.

              I think we largely agree as to the golden mean. Norvig’s solution is a high-water mark, but not one that I think we can reproduce in normal day-to-day software development. My question is how close we can get, given that our typical problems tend to be both larger and less well-defined.

              If you have the time and interest, I’d encourage you to follow the link to the glossary for “structure”, and read some of the relevant posts. I think you’d find that the term, as I use it, bears a pretty close resemblance to your “metastructure”.

              1. 6

                With all this talk about “holding the structure in your head”, I’m curious if you and @jfredett have read Peter Naur’s Programming as Theory Building and what your thoughts are?

                1. 1

                  I think it’s an interesting paper, but I don’t think the core metaphor has aged well. For instance, I don’t think this is true for many practicing developers today:

                  the programmer must be able to explain, for each part of the program text and for each of its overall structural characteristics, what aspect or activity of the world is matched by it

                  While “world” could mean anything outside the software, from his mentions of Kuhn and Popper I think it’s pretty clear Naur means the physical world. But today, a lot of software is separated from the physical world by countless layers of abstraction; the user is over the horizon, hidden from view. That’s why I’ve adopted a more linguistic approach; rather than talking about relationships between code and the world, I talk about relationships between text and paratext. I think this generalizes a lot better, and retains analytic power for all of the (good and useful) observations Naur makes about the relationship between software and its problem domain.

                2. 3

                  My question is how close we can get, given that our typical problems tend to be both larger and less well-defined.

                  I think we often forget the value of an initial research phase when approaching a novel problem. There might be papers, examples, blog posts etc on how to approach such a problem. This is how we’d discover novel techniques like the one Norvig used, so that we can use “Elvish ways” to solve “Elvish problems” instead of puttering about for too long.

                  1. 3

                    I think we often forget the value of an initial research phase when approaching a novel problem.

                    I agree, and I think this phase looks a lot like Joe, or a variant of Joe that is struggling to keep up with Peter instead of struggling to move as slowly as Ron. It’s a mix of undirected searching + following prior art; or, I suppose, staring at trees with Hobbits + chasing Elves through the woods, trying to keep up.

                3. 4

                  When I originally read Ron’s initial attempt at Sudoku, had I not already known who Ron was, I would have dismissed as particularly bad satire of TDD (and I’m not a fan at all of TDD!). I did not know he did a second attempt (much less that it took forty-five posts to finish it a few years later).

                  In fact, I think I might have spent less time than Ron writing a tool to help solve Sudoku puzzles, using raw Xlib calls. As you input the initial numbers, it will apply two of the simplest techniques for solving Sudoku (singles and hidden singles) and that alone is enough to solve every easy problem I’ve tried, and about half of the mid-level puzzles. What’s left is pretty easy to manage.

                  1. 4

                    I think you are missing the point, somewhat. In your analogy, Hobbit Ron does come out with something useful, just not the thing that was asked for. I think in reality this episode was more like Ron wandered around the woods for a while before stumbling into a high-speed intercity railway line to Thranduil’s court, but, too proud to turn back and wait for a train, walked along the tracks all the way to his destination.

                    The critical point here is that Ron did learn something useful by stumbling around. But his design philosophy forbade him from making the most of his new knowledge. You generally can’t choose between being Joe and Peter—you either know how to solve the problem on day one or you don’t—but hopefully at some point you will get to choose whether or not to be like Ron: you’ll learn something about how to solve the problem.

                    When Ron reaches this point, his beliefs mean that he can’t even acknowledge that knowing more would influence his design, so of course he won’t go back and redesign things. I think it’s fair to say this is just wrong, and one should aspire not to be like that.

                    1. 2

                      If you were Elrond and your team had one headcount, who would you hire?

                      It’s a nice parable, but I’m not sure it had the moral you intended.

                      1. 8

                        If I’m Elrond and I have to hire for just this task, obviously Peter is the best choice. However, he might also be the most expensive choice, and perhaps I have many more tasks in store, which might be more mundane or of a completely different nature, which Peter might not have the advance knowledge of that he did for this particular task.

                        Joe might actually be the better alrounder! Of course, if Peter is willing to work as a one-off consultant, that is probably the best move (and we could still hire Joe to do the implementation).

                        1. 1

                          Is the company you learned this at hiring?

                          1. 1

                            I’ve never been in Elrond’s position, so I wouldn’t say I learned this directly in practice. However, the company I work for now has been known to hire consultants for certain tasks, working together with the actual employees to ensure knowledge transfer.

                            I’m not sure if you were being snarky or serious here, but we currently don’t have any open technical positions that I’m aware of. You’re free to contact us anyway, of course.

                        2. 6

                          If Elrond just needs to get the message through, Peter.

                          If Elrond needs to map out all of Mirkwood (or Beleriand, as mentioned in the parable), Ron.

                          If Elrond is going to need someone to do subsequent work of unknown shape, Joe.

                          Everyone’s approach has value, there is no need to settle on any one. Don’t think arborescently, there isn’t a top to the tree, only a thousand blades of grass. My point is not that there is a right way, and in fact my question concluding the parable is facetious – they are all the best way, it depends on the circumstance.

                      2. 6

                        Looks cool!

                        There’s surprisingly little discussion about Earthstar here or on the orange sites. The only other discussion I could find is this. I also found the comparison helpful.

                        1. 2

                          This comparison surprised me. When I saw the website I thought of CouchDB or Litestream, not of the things they compared it with.

                        2. 3

                          I’m guessing the compression is lossy? Even though the process is deterministic, is it guaranteed that no information is lost?

                          1. 10

                            Arithmetic coding is mentioned so I suppose it’s using context modeling. I think the language model generates a sequence of bytes (a token converted to unicode), and that is interpreted as per-bit probability predictions. So based on the bits compressed so far (the “context”), the model outputs a prediction of the probability of the next bit being one. This prediction is used to help the arithmetic coder to compress the input better. If the prediction is wrong, the data will be still losslessly compressed, just with a worse compression ratio.

                            Context modeling compression (not sure what’s the right term) is a really cool method because you can just conjure up all kinds of weird predictors and if they work, you get better compression. Note that the decompressor must be able compute exactly the same predictions though.

                            Edit: A quote from the ts_zip page:

                            The language model predicts the probabilities of the next token. An arithmetic coder then encodes the next token according to the probabilities.

                            1. 4

                              It’s lossless, but some models have different trade off. rwkv_169M_q8 is slower but works on GPU and give consistent results. You can use other models, like llama based ones, and they accept cuda for a speed up, but then you can only decompress things using the same combination of model + GPU + software version.

                              1. 1

                                It’s lossless. Click through to the ts_zip page to learn how it works.

                                1. 1

                                  Maybe I’m blind, but that page doesn’t really say anything about whether ts_zip (and by extension ts_sms) is lossless or not. The only bit that alludes to lossyness is “and hopefully decompress”, which I indeed interpret to mean that it is lossy.

                                  1. 2

                                    The LLM needs to be deterministic for decompression to work.

                                    1. 5

                                      Is that enough? An algorithm that maps all inputs to the string “FOO” would also be deterministic (and compress well), but it would be lossy.

                                      1. 3

                                        No, determinism not enough. If two or more inputs compress to the exact same output, then the compression is lossy and not fully reversible. In other words, the compression function must be Injective to be lossless.

                                        1. 4

                                          The normal way of turning a lossy compression scheme into a lossless one is to compress, decompress, and then encode the delta somehow. Generally, the delta is much smaller than the original input and so can be stored uncompressed, though there are better techniques that compress it (you can also nest this process, applying a lossy compression scheme to the deltas and then storing the deltas of deltas).

                                          A lossy compression scheme is never infective, by definition: it discards information, so two similar (within whatever state space the encode uses) inputs will give the same output. This doesn’t matter, it just means that, if A and B map to the same compressed then decompressed C that you need to store A-C and B-C to be able to decompress A and B. And hopefully this is smaller than the size difference between A and C or B and C.

                                          1. 2

                                            Interesting, that was very informative, as always.

                                            One question comes to mind (with the caveat that I’m no expert in either encryption or LLMs): Given that LLMs predict the next token in part dependent on previously outputted tokens, it seems to me that there is a chance that one wrongly predicted token early in an output stream could lead to divergent results. Given that we have to store a delta, is it possible that the compressed data (with delta) could actually be larger than the uncompressed data?

                                            For instance, I could have compressed the string “The quick black rabbit leaps above the sleeping cat”. Let’s say that the decompression results in a string that starts with “The quick”. The LLM determines that the most likely next word is “brown”, which might be fine if that was all that was different from the original string, but seeing “The quick brown”, it might determine that the most likely next word is “fox” instead of “rabbit”, etc. The result would be something that decompresses to “The quick brown fox jumps over the lazy dog” and contains deltas for all words except the first two, and which would likely take up more space than the original input.

                                            I’m wondering whether it would be possible to construct such an adversarial input for ts_sms and ts_zip…

                              2. 4

                                From a Git perspective, jj is very “rebasey”. Editing a file is like a git commit –amend, and in the “fix a typo” move above the edit implictly rebases any downstream commits.

                                That sounds extremely elegant and terrifying at the same time. With git, I often mess around on old commits and then decide to abandon my attempt by using “git checkout” or “git rebase –abort” and know that I will get back to a pristine working copy of the upstream repo.

                                Similarly, just doing “git checkout” to switch to a different branch I might have some local changes I forgot about. Having those implicitly auto-committed sounds rather dangerous to me. How does jj prevent accidentally pushing work-in-progress changes?

                                1. 7

                                  A common flow is to jj new COMMIT (which puts you on a new commit descending from COMMIT). You can squash changes back into the parent interactively, which means you’ve essentially DIYed your own “index”. Except, if you instead decide you want this set of working changes to be its own commit, you can just leave it in the new one. Maybe you then rebase this commit (e.g. jj rebase -r @ -B xyz where xyz is the commit following your target in the main line), to put this as a new commit in after. Or whatever, you can throw it around anywhere, squash it, leave it. The unit is a commit.

                                  edit to add: also, you can just jj op undo if something didn’t work! All snapshots are saved, so you can rewind to any point you ran any jj command, including just status, etc.

                                  edit to elaborate: those local changes, then, would be on their own commit. You wouldn’t accidentally push it, because it’s clearly a WIP commit. You probably haven’t given it its final description yet, there’s other random stuff in there you don’t intend to push. Bookmarks (for git tracking purposes) don’t get moved automatically; you explicitly do it. It turns out this works well.

                                  1. 2

                                    That makes sense, thanks!

                                  2. 7

                                    One thing I didn’t learn until using jj in anger on a shared repo with lots of branches and frequent committers, is that leaf commits (w/o an associated bookmark) are automatically ‘suspect’ in jj, because you don’t only “checkout a branch” — you jj new cool-branch@origin instead. You’re now on an empty commit (and the UI marks empty commits in many places for good reason), and if you move off it without making any changes, it automatically vanishes (gets abandoned).

                                    If you happen to make some local changes first, maybe you play around with something, then those are of course saved in that new commit until you explicitly drop them. If you check something else out and then want to return, unlike git I don’t look at the branch list, I jj log and it shows everything relevant, including my leaf commit on top of a commit that has cool-branch@origin next to its ID. So I see it and go, right, there’s my old WIP or whatever, I’ll edit that, or new that, or whatever. If I later jj git fetch and that cool-branch@origin has moved, I’ll still see my old WIP commit poking out of the branch halfway, and I can rebase it on top of the new branch head and then edit it. (You can do it the other way around, like git, as well — edit it, and then rebase it — but isn’t it cool that the working copy truly isn’t privileged in this way? You don’t have to focus the Eye of Sauron on a commit to rebase it. Heck, you can rebase multiple disparate commits with a revset all at once.)

                                    1. 9

                                      Sounds pretty cool. I’d like to try jj but I’m still sort of stuck with git due to relying so heavily on magit and wouldn’t want to lose it. I barely interact with git directly on the CLI myself anyway. But of course magit is still strongly tied to the git workflow and mindset.

                                      1. 5

                                        I never got the hang of magit even though I code in emacs all day. I’ve also gotten tired of using the CLI with git and had a lot of my own keybindings setup in .emacs. For jj, I didn’t want to drop back into the CLI which is why I wrote jj-fzf. For my purposes, it is more visual than magit and I made sure all hotkeys to execute jj commands are discoverable by default. You can take a peek at it in the screencasts here: https://github.com/tim-janik/jj-fzf?tab=readme-ov-file

                                        1. 1
                                        2. 3

                                          As a data point, I needed magit because git UX is clunky and slow, with jj everything is so streamlined I dont feel I miss magit that much. Id still like to have it, but it has been fine because the amount of time I spend with the jj cli va the git cli is a lot less. Give it a try! I had the same reluctance to use it due to magit.

                                          1. 2

                                            I feel you. I’m also waiting on something like magit for jj…

                                            1. 2

                                              If that helps, I’ve created an implementation of the vc.el interface for jj, with an added sprinkle of project.el

                                              https://codeberg.org/vifon/vc-jj.el

                                          2. 6

                                            With git, I often mess around on old commits and then decide to abandon my attempt by using “git checkout” or “git rebase –abort” and know that I will get back to a pristine working copy of the upstream repo.

                                            It’s interesting to note that Git doesn’t have a facility to undo that undo operation, while jj does:

                                            • In Git, you can’t say “actually, I want to resume that rebase I started” and jump back directly into what you were doing.
                                            • In jj, all of the intermediate rebase states are just commits, so there’s no secret extra state (like the .git/rebase-merge directory) that tracks the rebase.
                                            • In jj, you can use jj undo to undo an arbitrary operation.

                                            So jj should actually be safer once you get used to it.

                                            Similarly, just doing “git checkout” to switch to a different branch I might have some local changes I forgot about. Having those implicitly auto-committed sounds rather dangerous to me. How does jj prevent accidentally pushing work-in-progress changes?

                                            There are a few default mechanisms:

                                            • When creating a new commit, jj won’t automatically “advance” the branch pointing to its parent commit. Many commits are therefore not addressable by branches by default, so you wouldn’t easily be able to accidentally push them.
                                            • jj git push will refuse to push commits without a description, and jj new will create commits without descriptions by default.
                                            • There’s the git.private-commits configuration setting to configure your own set of commits that shouldn’t be pushed.
                                          3. 6

                                            Maybe someone in here can help answer my question.

                                            I really like working with stacked diffs. At my company, we’ve recently taken up Graphite, which offers a great workflow around stacked diffs, while being completely compatible with git and GitHub. In particular, it allows a great reviewing experience, where each “commit” gets its own branch on GitHub, which you can comment on, update and so on. Graphite then takes care of stacking them, merging them in the right order, changing the order around as desired, etc.

                                            I get that jj offers some of the same benefits around working with stacked diffs, but I’m having a hard time understanding how people use jj to collaborate with others. Do you still just create old-fashioned PRs with lots of commits in them? How do you review these, especially if a commit in the “middle” of a PR changes? Does using jj in a team effectively require you to adopt Gerrit or something like that?

                                            Edit: Graphite has a bunch of marketing fluff about AI features. You can safely ignore that and just use it for the great PR reviewing and stacking features it has.

                                            1. 3

                                              For use with github, the idea is to create multiple stacked PRs, same as graphite does. However, the forge integrations in jj are still WIP, so people either do it manually, use a script, or some external tooling for now.

                                              1. 1

                                                I see, that’s what I expected. I really like how easy Graphite makes it to create new stacked PRs and even reorder them or restack them while they’re being worked on. I also don’t mind doing it manually, but I think it would be an unnecessary burden to put on my colleagues.

                                                Edit: And thanks for explaining :-)

                                            2. 46

                                              To me the key insight is from a comment: “it’s easier for LLVM to vectorize Rust than C because Rust emits noalias annotations almost everywhere.”

                                              Other than that, the speed boost seems to come from being smarter about how to do the gzip decompression, and adding explicit SIMD code paths, neither of which have anything to do with Rust; but it’s nice to see memory-safe code can hold its own in performance.

                                              1. 51

                                                Noalias is finally starting to pay off. The png crate copied Paeth filter from stb_image, but the same code autovectorized even better in Rust.

                                                neither of which have anything to do with Rust

                                                I think there are also less tangible benefits that contributed.

                                                It’s easy to use dependencies, and try out multiple implementations. Inlining across libraries works out of the box, so the codec got SIMD-optimized Adler32 for “free”.

                                                It’s also easy to provide libraries for others to use, without wasting time on tweaking #ifdefs and build scripts (zlib has more commits changing Makefile.in and zconf.h than inflate.c).

                                                There’s built-in unit testing, so you can experiment with implementations without breaking stuff (BTW, I have no idea how zlib is tested — is that it!?).

                                                There’s painless tooling for running accurate benchmarks (on modern CPUs with complex thermal management it’s really hard to get accurate numbers when you’re trying to squeeze every 0.5% of performance).

                                                Rust can be quite high level and still performant, so despite the performance, most of the codec’s code is fairly boring.

                                                1. 23

                                                  This. I don’t think the take-away from this story should be “Rust enables performance that C doesn’t”. Instead, the story is: “The features of Rust free up developer brainpower to focus on the last of Make It Work, Make It Correct and Make It Fast instead of the first two”. And by this, I don’t just mean memory safety.

                                                  It would be interesting to compare how many man-years have been put into those libraries. Presumably, the Rust folks have the advantage of reference C-implementations to look at, but those C-libraries have probably been around for way longer. Presumably, all the same optimizations that made the Rust implementations fast are also viable in C, so how come no-one has done them?

                                                  My guess is that the features of Rust allow developers to fearlessly refactor and try out different architectures, designs, libraries, extensions and so on, without fearing for correctness.

                                                  1. 3

                                                    (BTW, I have no idea how zlib is tested — is that it!?).

                                                    When I submitted code to zlib a million years ago, it was just “run it on a few large files”. Admittedly, for the change I was making, pretty much any file larger than 1kB tested every conceivable code path I touched, so I accepted that. (I wish now that I had also submitted some kind of really basic automatic test, which would have made it easier to gradually add more tests to, but at the time I was just happy that my change was being accepted at all.)

                                                    1. 1

                                                      Inlining across libraries works the same in Rust and C so I’m not sure what you mean. In both languages it won’t happen across libraries without an explicit inline annotation unless you use LTO.

                                                      1. 13

                                                        Rust has changed that. Now all “small” functions are inlining candidates by default. ThinLTO is also used by default.

                                                        Standard practices for C libraries, like use of opaque types for privacy, are not inlining friendly. Rust’s lack of ABI stability happens to work in its favor here.

                                                        1. 3

                                                          Small functions are only inlining candidates if they are in the same translation unit (just like C) or subject to the “local LTO” that doesn’t work across library boundaries.

                                                          The ThinLTO default is “local LTO” and only applies within a crate, which traditionally in Rust was one translation unit. They need that “local LTO” in order to compensate for the fact that the compiler now tries to split crates up into multiple units, which actually limits how much inlining can be done. So that feature is to get Rust back to being as good as C, not an improvement.

                                                          1. 6

                                                            Small functions are only inlining candidates if they are in the same translation unit

                                                            The thing I’m talking about is called cross_crate_inlinable query, and it adds the exact equivalent of #[inline] to “small” functions, specifically to cross the translation units. Added in 1.75. It has reduced need for #[inline] spam on getters, setters, and simple ctors.

                                                            1. 1

                                                              TIL! I guess it’s fine as long as there’s no stable Rust ABI.

                                                            2. 4

                                                              They need that “local LTO” in order to compensate for the fact that the compiler now tries to split crates up into multiple units, which actually limits how much inlining can be done. So that feature is to get Rust back to being as good as C, not an improvement.

                                                              A crate is often much bigger than what your average C project puts into a single translation unit, so this doesn’t really seem true.

                                                              1. 1

                                                                Even so, it’s not an improvement over a C project putting an inline function in a header. In that case in C both the library itself and external users can inline.

                                                          2. 7

                                                            I don’t believe that’s the case. My understanding is that without LTO

                                                            Rust and C both inline within a translation unit whenever the compiler think it’s a good idea or almost certainly if the program told them to (rust’s #[inline(always)] and a similar attribute for most C compilers).

                                                            Rust currently further inlines across translation units for all generic functions, and whenever the function was marked #[inline] or #[inline(always)], C has no equivalent to either. Rust further maintains the right (that it doesn’t currently exercise) to do the same to other functions, while C does not.

                                                            C further inlines across translation units when you stick the function definition in a header with static or inline, by virtue of each translation unit seeing a different copy of the function. Rust has no equivalent to this.

                                                            Notice that the cross-translation unit method in rust simply requires adding an annotation to the function, while the C version involves changing the location of the function in the source. The rust version also doesn’t effect semantics (e.g. function pointer equality) while I believe the C version does.

                                                            1. 1

                                                              Everything you said is consistent with what I said. It’s the exact same model, the only difference is whether it’s an annotation or whether it’s an annotation plus putting the function in the header. C++ templates are also implicitly inline, that’s where Rust got the behavior!

                                                              1. 1

                                                                Seems I can’t edit anymore so self reply

                                                                Rust further maintains the right (that it doesn’t currently exercise) to do the same to other functions

                                                                Per Kornel’s comment above rust has actually started exercising this right.

                                                            1. 13

                                                              IIUC this is one of the reasons that Fortran has long outperformed C in heavy number-crunching workloads as well. By default it has much stricter aliasing rules so unless very careful work is done in C Fortran will often out-perform it.

                                                              1. 1

                                                                This is the exact opposite of my experience: Rust bounds checks and panics usually prevent vectorization where it would have succeeded in C. Even if you don’t use array indexing Rust still inserts checks on every division and bit shift the latter of which are very common in SIMD code. And explicit SIMD is unsafe to boot.

                                                                1. 4

                                                                  Does putting an assertion at the top about the divisor being non-zero help? That’s generally helped in the past.

                                                                  1. 7

                                                                    To add to this, integer types in Rust have functions for explicitly wrapping or overflowing bit shifts if you want something that’s defined for all values and won’t panic.

                                                                    If you’re confident that you won’t overflow and thus don’t need the auto-generated checks (and don’t want unsafe), then you may as well use one of those since the situation won’t come up.

                                                                    This is assuming that the overflowing or wrapping shifts have vector equivalents in your ISA.

                                                              2. 3

                                                                I was surprised at the lack of a mention of Erlang. Even Alan Kay sees it as an implementation of his notion of OOP:

                                                                Significant parts of Erlang are more like a real OOP language the the current Smalltalk, and certainly the C based languages that have been painted with “OOP paint”.

                                                                Also see this quote from Joe Armstrong:

                                                                Erlang has got all these things. It’s got isolation, it’s got polymorphism and it’s got pure messaging. From that point of view, we might say it’s the only object oriented language

                                                                1. 5

                                                                  I originally had some slides on Erlang and its descendants, but had to cut a bunch of content to fit the time slot, and that was one of the earliest cuts because it felt like too much of a rabbit hole to explain the contested history around what paradigm(s) Erlang should be categorized under. Depending on who you ask, Erlang is either object-oriented, or functional, or both, or neither.

                                                                  The full context of Joe’s quote can be found at 8:45 in that video clip you linked. He talks about how his view used to be that Erlang was functional and that OOP was “silly” (the word he used in the title of the blog post was “sucks”), but then he questioned this view when his thesis advisor told him “Joe, you’re wrong, Erlang is extremely object-oriented; all the [mainstream] ‘object-oriented’ languages aren’t object-oriented” and then Joe’s exact quote from that clip was: “I might think - I’m not quite sure whether I believe this or not - but Erlang might be the only object-oriented language” (which he then goes on to explain is based on Alan Kay’s 2003 definition of OO as being all about message-passing).

                                                                  I think most people today consider the Erlang family of languages to be functional. Consider that Gleam self-describes as functional on the website—and originally even used Elm syntax—and that Elixir not only self-describes as functional on its website, but also Pragmatic’s two books on Elixir both have “Functional” in the title, and Manning and O’Reilly’s books describe Elixir as functional in the description. There’s no mention of OO anywhere in any of those. The view that Erlang is object-oriented tends to mainly come up in the context of “Actually, here’s something that’ll blow your mind - did you know that Erlang can technically be thought of as extremely object-oriented? Seriously! Let me explain…” - the reason this is such a neat story is that it subverts the common understanding of Erlang being a functional—or at the very least not object-oriented—language.

                                                                  It would seem strange to me to use Elixir’s popularity and Gleam’s rising popularity as examples of OO having a bright future as a paradigm, when the functional paradigm is far more commonly associated with those languages. To put it another way, the claim “Newer OO languages are growing in popularity, just look at this family of languages that use immutability everywhere and don’t have any classes or methods or inheritance or even use the term ‘objects’” sounds contradictory for good reason.

                                                                  The other reason I didn’t bring them up is that, as fond as I am of Erlang and the family of languages that have grown out of it, none of them have reached mainstream levels of popularity. Even if you want to make the case that their popularity is reflective of OO (and not functional programming) becoming more popular, we aren’t talking about mainstream levels of popularity—at least not today—so the impact on the macro-level trend is necessarily much smaller than the languages I focused on in the talk (Rust, Go, C, etc.).

                                                                  Similarly, I also like Zig quite a lot, but I only mentioned it briefly because it’s not in the same tier of mainstream adoption as those languages—again, at least not today—and I didn’t see a way to briefly mention Erlang or its descendants without going down a rabbit hole given its contested history!

                                                                  1. 1

                                                                    I had the same thought. And, looking at the rise of Elixir, Kayian OO may be at its all-time peak in popularity.

                                                                  2. 16

                                                                    Congrats! I’m continually impressed by the features that you ship so frequently. Good job!

                                                                    1. 4

                                                                      I wonder what is that lets them ship new features so fast, compared to other proglangs.

                                                                      And they seem well designed, non-hacky additions.

                                                                      1. 4

                                                                        I’ll take some guesses:

                                                                        • less red tape compared to heavy-corp langs
                                                                        • rust core
                                                                        • still relatively young, so lots of low-ish hanging fruit still there
                                                                    2. 11

                                                                      These use expressions are a really interesting idea. This might also fit a lot of non-FP languages with closures.

                                                                      1. 2

                                                                        They seem very similar if not identical to Koka’s “with” statement. Very cool idea either way.

                                                                        1. 1

                                                                          It looks equivalent to the await expression in languages with async/await.

                                                                          1. 12

                                                                            It’s more general than that. It can be used to implement async operations, but also so much more. It’s basically syntactic sugar for continuation passing style.

                                                                            1. 6

                                                                              Yeah, it’s the first time I’ve seen a PL make CPS style not immensely annoying to read.

                                                                              1. 7

                                                                                I know, right?! When I realized what it was I bust into the Gleam Discord and asked “omg do you realize what you have done?!” and the response was just “oh yeah, totally”. I next asked whether they had any grand plans for extending it into async or coroutines or other fancy advanced language features and the answer was “maybe someday, but right now we’re pretty happy just having an equivalent of Rust’s ? operator”. For some reason that struck me as very charming.

                                                                                1. 1

                                                                                  They mostly run on JS or the BEAM so cooperative multitasking probably doesn’t buy Gleam much value. Maybe if it turns into a natively compiled language!

                                                                            2. 4

                                                                              Not that complicated afaik. The following Gleam code:

                                                                              use x <- foo
                                                                              body
                                                                              

                                                                              is equivalent to the following OCaml (using a binding operator):

                                                                              let ( let@ ) f x = f x in
                                                                              ...
                                                                              let@ x = foo in
                                                                              body
                                                                              
                                                                          2. 5

                                                                            I didn’t read all of this, but this bit immediately jumped out to me:

                                                                            type UserSession struct {
                                                                              Username string
                                                                              pwHash string
                                                                              expires time.Time
                                                                            }
                                                                            

                                                                            By default, you’re one fmt.(Sp|P)rintf(”%v\n”, session) away from including a user’s password hash in your logs, writing it to a file, or returning it in a server response.

                                                                            Type systems as they exist today are unable to prevent this kind of bug. A string containing a user’s name is indistinguishable from the string containing their salted+hashed password at compile-time. While some tools and techniques exist to mitigate these issues, they’re at-best difficult to set up and at-worst (and most commonly) not attempted at all.

                                                                            Hard disagree. It is trivial to prevent this in Rust via implementing Debug manually and hashing out pwHash.

                                                                            use std::fmt;
                                                                            use std::time::Instant;
                                                                            
                                                                            struct UserSession {
                                                                                username: String,
                                                                                pw_hash: String,
                                                                                expires: std::time::Instant,
                                                                            }
                                                                            
                                                                            impl fmt::Debug for UserSession {
                                                                                fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                                                                                    f.debug_struct("UserSession")
                                                                                        .field("username", &self.username)
                                                                                        .field("pw_hash", &"xxxxxxxx")
                                                                                        .field("expires", &self.expires)
                                                                                        .finish()
                                                                                }
                                                                            }
                                                                            
                                                                            fn main() {
                                                                                let user_session = UserSession {
                                                                                    username: "munksgaard".to_string(),
                                                                                    pw_hash: "hunter2".to_string(),
                                                                                    expires: Instant::now(),
                                                                                };
                                                                                println!("{:?}", user_session)
                                                                            }
                                                                            

                                                                            Try it yourself

                                                                            Edit: Alternatively, create a separate Password struct that doesn’t implement Debug and you’ve essentially achieved the same thing.

                                                                            1. 9

                                                                              Edit: Alternatively, create a separate Password struct that doesn’t implement Debug and you’ve essentially achieved the same thing.

                                                                              Or do implement debug but make it output some fixed string, so that you can derive Debug on structs that contain your Password type:

                                                                              use std::fmt;
                                                                              use std::time::Instant;
                                                                              
                                                                              struct Password(String);
                                                                              impl fmt::Debug for Password {
                                                                                  fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
                                                                                      f.debug_tuple("Password").field(&format_args!("_")).finish()
                                                                                  }
                                                                              }
                                                                              
                                                                              #[derive(Debug)]
                                                                              struct UserSession {
                                                                                  username: String,
                                                                                  password: Password,
                                                                                  expires: Instant,
                                                                              }
                                                                              
                                                                              fn main() {
                                                                                  let user_session = UserSession {
                                                                                      username: "munksgaard".to_string(),
                                                                                      password: Password("hunter2".to_string()),
                                                                                      expires: Instant::now(),
                                                                                  };
                                                                                  println!("{:?}", user_session)
                                                                              }
                                                                              

                                                                              Try it yourself

                                                                              1. 3

                                                                                Yep, I totally recognize that it’s possible (+ @square_usual’s comment – sibling to this). I mention these approaches in “Custom Serialization”. The main drawback is that it’s still possible to access the pw_hash struct field directly and log it, write that to a file, concatenate it with some other strings, etc.

                                                                                1. 4

                                                                                  It’s very possible that I’m overlooking something, but I just don’t think that’s true. At least not in Rust (or similar ML-like languages): You wrap the UserSession in a module and only export functionality you need outside. Example. Notice that if you uncomment the last line of main, you get a compile-time error, because pw_hash is not accessible outside of the user_session module.

                                                                                  1. 7

                                                                                    With the proposed system you couldn’t log pw_hash even within the user_session module. It would also protect you from accidentally implementing a version of fmt::Debug that printed the actual value.

                                                                                    There are examples like this in the post already.

                                                                                    1. 3

                                                                                      (@lcapaldo’s peer comment is correct. This was already written though 😅)

                                                                                      Yep! That’s pretty standard domain-driven design. Expanding that one step requires reading the hash from a database via a database singleton or a repository pattern or whatever you prefer. But the fact remains that something has that value and can do something ill-advised with it :)

                                                                                      1. 2

                                                                                        I see. I’ll read through your post more carefully. Thanks to you and @lcapaldo for taking the time to explain.

                                                                                    2. 4

                                                                                      Honest question here: what’s so bad about printing the password hash? It’s not the password, it’s the hash (a one-way function that is hard to reverse). The whole reason is to store a password safely (rather than the actual plain text password). If you are worried about rainbow attacks, then use a better hash.

                                                                                      1. 3

                                                                                        what’s so bad about printing the password hash?

                                                                                        Probably nothing, to be honest! I’m channeling my inner security engineer with that, and it’s likely a bit overly-worried.

                                                                                        s/password hash/session token/ and the general idea still applies though. We need to decrypt and validate the session token, but logging it means anyone with log access can impersonate the requesting user.

                                                                                        1. 2

                                                                                          I think session tokens would make a better example of the issue.

                                                                                          1. 2

                                                                                            Or unhashed passwords, which the server briefly needs to deal with whenever a user logs in.

                                                                                    3. 4

                                                                                      The ML family functional languages have largely prefered this style of programming for decades—& the same arguments for prefering a functional style using ADTs over object-oriented/imperative exceptions. Is Rust actually doing something new?

                                                                                      1. 15

                                                                                        I’ve never personally seen people in the Rust community claim that the core concepts in Rust are unique discoveries but practically every full moon I see a bunch of comments to the effect of “don’t people realize none of this is new”, which is pretty funny.

                                                                                        Of course none of it is new, because we develop software where famously no innovation sees popular light until at least a decade of obscurity, sometimes sadly more. Almost all engineering projects in the space are just rearranging existing techniques into domain-specific applications, because innovation is naturally feared by the programmer. Sometimes ignorantly, although usually for good enough reasons.

                                                                                        1. 8

                                                                                          There is nothing new in Rust, at all.

                                                                                          Intent is to pick stuff widely known to be good, and be thorough, not botch any one part so bad.

                                                                                          http://venge.net/assets/talks/intro-talk.pdf via http://venge.net/graydon/talks/

                                                                                          1. 7

                                                                                            No, but it has brought those concepts to the masses.

                                                                                          2. 17

                                                                                            There’s an under-appreciated technical part to this: type systems restrict the set of programs you can write. If you design a type system well, you can remove a bunch of invalid programs from the set – e.g. those with memory safety bugs or data races – but you’ll necessarily remove valid programs too. In general, it seems that the stronger (more robust, more capable?) your type system is, the smaller that set will be. More glibly, e.g. all (safe) Rust programs are data-race free, but not all data-race free programs can be written in Rust.

                                                                                            Pure speculation: I bet there are kernel subsystems that are valid, i.e. are of sound design, but with semantics that aren’t easily expressible in Rust. For temporal safety (double free, use-after-free, etc.), this is probably less of an issue, but for things like data race safety, or higher level semantics like how inodes get initialized, there may be impedance mismatches.

                                                                                            In this light, “tell [us] what the semantics are” lacks nuance. To illustrate, at 34:45 in the talked linked from Wedson’s email one of the speakers says “I realized into the talk this maybe wasn’t the first thing to throw up there because this is the complicated case,” and a member of the audience, who presumably knows the VFS subsystem responds “oh no it is not.”

                                                                                            There’s a lot of confidence from Rust folks that Rust will obviously work in the kernel and this is just a matter of getting cooperation from recalcitrant kernel devs. I don’t think it’s that simple.

                                                                                            I’ve run into similar situations in Swift. E.g. there’s a disconnect between how Swift wants you to write programs that are provably data-race free, and NSDocument’s older multi-threaded APIs, which are equally valid but not expressible in Swift.

                                                                                            TBC, I don’t think this is the primary thing going on. It’s the questions about how the pain will be distributed and how honest (with themselves and others) the R4L people are being when they say “you won’t have to learn Rust.” But I’m sure it’s playing a part.

                                                                                            1. 17

                                                                                              “oh no it is not.”

                                                                                              If it’s simple, then they should be able to describe the contract. The contract they ought to be able to describe might well be incompatible with Rust’s view of things, but we have no way of knowing, since we haven’t even gotten to that part!. Someone who understands the contract should be able to describe it in a way that another C programmer can make use of. They appear to be unable or unwilling to do this. Therefore I find it extremely unlikely that it’s actually simple.

                                                                                              Pure speculation: I bet there are kernel subsystems that are valid, i.e. are of sound design, but with semantics that aren’t easily expressible in Rust.

                                                                                              Personally I would bet that there isn’t a single subsystem or non-trivial module that doesn’t have UB.

                                                                                              1. 9

                                                                                                edit: given @munksgaard’s comment below, it seems like you and I might have interpreted “oh no it is not” differently, so some of my response might read as a bit confused. After listening again, I think my interpretation is correct (again see below): the audience member is saying, “it’s way more complicated.”

                                                                                                If it’s simple, then they should be able to describe the contract.

                                                                                                Sure, I agree with that – this should be true even if the contract isn’t simple, and the reluctance to do that is definitely frustrating. I think the root cause of that conflict is more related to the primary issues: distrust, pent up frustration, etc. I’d give the kernel devs the benefit of the doubt and say that they are unwilling, not unable to describe the contract. Obviously, that’s frustrating.

                                                                                                Therefore I find it extremely unlikely that it’s actually simple.

                                                                                                I think we agree? I don’t think it’s simple, and I pulled those quotes to show that it likely isn’t. In effect, the speaker said “this example is the complex case” and the audience member said, “there are way more complex cases than that.”

                                                                                                Personally I would bet that there isn’t a single subsystem or non-trivial module that doesn’t have UB.

                                                                                                Well sure. The kernel definitely has UB, and writing parts of it in a language that forbids UB (putting aside unsafe Rust) is obviously valuable. But that’s beside the point. If there are maintainers who believe that Rust will be incompatible with how their subsystem is architected, it’s not going to make them more excited about R4L. Obviously that’s annoying, but that doesn’t make it go away. And if Rust advocates approach situations like this without some humility, it contributes to the attacks that Rust is a “religion.” N.b. I don’t think the R4L people are doing that, but in the wider discourse, there’s a lack of humility on the part of Rust advocates, and I think it contributes.

                                                                                                1. 3

                                                                                                  You could also interpret the “oh no, it’s not” comment as agreeing with the presenter that this was a bad example, implying that it is indeed a difficult case. I’m not sure which interpretation is the correct one, I just wanted to point it out.

                                                                                                  1. 6

                                                                                                    Just took another listen. Right after “oh no it is not,” another audience member says “we have much more complicated cases, but this is not a trivial case.”

                                                                                                    Still a good point though. I hadn’t thought of that, and it made my original post less clear than it could have been.

                                                                                                2. 8

                                                                                                  Yes, I made the basically same point here - https://lobste.rs/s/46pt2l/retiring_from_rust_for_linux_project#c_gcmz5r

                                                                                                  I didn’t have time to reply to all those comments, but I’ll repeat the point

                                                                                                  Ted Tso mentioned that we will find out OVER TIME if it “the idea of encoding huge amounts of semantics in the type system is good idea” – because “maybe we’ll start using <some variant of> RCU” (for example)


                                                                                                  So then I go look at RCU (which I’ve read about several times, but never used). It apparently has at least 5 variants

                                                                                                  https://en.wikipedia.org/wiki/Read-copy-update#Sample_RCU_interface

                                                                                                  https://lwn.net/Articles/653326/#Other%20RCU%20Flavors

                                                                                                  I don’t know if Rust can express any of this statically, and reasonably. I don’t think anybody knows TBH. And I certainly could be underestimating what Rust type’s system can express.

                                                                                                  But many people replied to me with certainty that Rust can express it. There is a confidence that IMO is not matched by experience.


                                                                                                  My suspicion is basically that Rust can express something like what Linux uses, but not actually what Linux uses, which makes migration very problematic.

                                                                                                  And if you try to express exactly what Linux uses, it will either be impossible, or you will end up with 20 line type signatures that help nobody.

                                                                                                  Similar situation with C++ (which has always been rejected by Linux).

                                                                                                  C++ has a type system that’s more expressive than Rust in some dimensions (and with gaping holes due to C compatibility). But over time a consensus has emerged that there are severe downsides to “maxing out” the statically typing philosophy.

                                                                                                  Or it’s probably more accurate to say there’s an ongoing decades-long debate about how much to express in the type system, just like there is with Rust – even among Rust programmers, completely separate from the Linux kernel (e.g. recent story https://lobste.rs/s/zmgjxm/writing_apis_rust_2022 )


                                                                                                  Of course Rust is not C++, and Rust is a genuine advance in many respects. So I basically repeat the challenge – show us it works! (not me, but the kernel community)

                                                                                                  There are other experienced kernel programmers and Rust programmers in the thread who are doubtful of Rust+Linux for the same or similar reasons, but they seem to have been drowned out by a mob!

                                                                                                  1. 22

                                                                                                    So, this comment is very strange in much the same way that Ted Tso’s response was.

                                                                                                    This is in the context of R4L people asking questions about what invariants the C programmers expect to hold, as they have explored the codebase and it does not seem to hold the invariants that people think it does, and also the documentation is wrong or just nonexistent, so that the R4L people can work on a good encoding on the Rust side, where the C programmers simply refuse; but when the R4L people come in with Rust encodings of the actual invariants discovered through extensive code archaeology along with patches to fix the places where the C code does not actually hold those invariants and has memory safety bugs, they get rejected; and then the kernel C devs who are opposing Rust say all three of ‘no one can know if Rust could do this’ and also ‘I’ll break your Rust stuff on purpose to screw you over you religious zealot’ and also ‘I’m being reasonable here, no one can possibly know if Rust can do this, maybe in five years time we will know, so go away’.

                                                                                                    So, people are noticing that the kernel C devs who are opposing Rust are saying some real nonsense, and your reply to that is to… say the same kind of nonsense?

                                                                                                    We know that Rust can do some of this kind of stuff, because the R4L people came with patches. Of course the Rust type system can’t do every hypothetical thing - but that isn’t a real objection to ‘here are patches that fix real longstanding issues with this stuff, so at least some of these things can definitely be fixed by Rust, and we have reason to believe the rest can too; but please let us know what the invariants are supposed to be for this other stuff so we can do the work to find out whether Rust can work here or not now’.

                                                                                                    1. 6

                                                                                                      I agree with most of this (immediate parent) comment, but I don’t think it’s fair to compare grandparent to Ted Tso’s comments. It’s not overtly hostile in the same way, even though it is throwing up… strange objections.

                                                                                                      1. 5

                                                                                                        I think we’re talking past each other in EXACTLY the way I mentioned in that very first comment , which was the whole point I was trying to make about the inherent difference in mindset …

                                                                                                        These viewpoints are clashing:

                                                                                                        1. the static viewpoint where of course it’s a good idea to be asking about the semantics and encoding it in the type system
                                                                                                        2. the dynamic viewpoint, where this is an empirical question

                                                                                                        Is it an empirical question?

                                                                                                        What I saw skimming one mailing list thread showed disagreement over the patches. Kernel developers were saying these read-only file systems are “toys”, which I presume means that the abstraction wasn’t tested, and doesn’t represent reality as they understand it


                                                                                                        Also I’d say if you go to any place I’ve ever worked, and say “we would like to know the semantics so we can encoded it in the types”, then you will not get a straightforward response.

                                                                                                        You will probably be signing yourself up for a lot of work, and you will probably not get much done in the end.

                                                                                                        You might get a weird look. That’s not to say that things can’t change, but just an observation

                                                                                                        You could try this on a project that’s not Linux, and see what happens

                                                                                                        1. 17

                                                                                                          Are you serious?

                                                                                                          Edit: So, the thing that had me post my ‘hey, this is similar to Ted Tso’s replies’ was how you keep saying stuff that is in the form of a reply, but which doesn’t actually connect, such that the ‘other side’ either has to follow where you went and concede their point without you actually having countered it in order to keep having a conversation, or they end up in ‘increasingly flustered wtf’ territory. That is interesting to me. But just in case you are not doing it on purpose, the point is that what you are saying does not make sense as a reply in this context. We were in the context where Rust was shown to be able to do some of the stuff (and there was no ‘this is a toy example’ in the patches that AsahiLina wrote, so I’m not sure where you are getting that), (edit: and where the stuff that Rust can do that you are sort of abstractly gesturing at maybe being under debate has already been agreed to be good), and where the kernel C programmers have long said ‘our APIs have specific semantics that are explicit and known, which is why they are good, and why bugs are a skills issue rather than anything else’, and where the R4L people are then saying ‘okay, the semantics are not in the documentation, nor are they in the places where the code is used as you claim that the bugs at the use sites show that the users don’t understand the semantics, so can you tell us the semantics then, so we can write them down and try to code against them?’.

                                                                                                          1. 2

                                                                                                            Yes, I’m 100% serious! I think there is a difference in mindset that is resulting in the communication problems

                                                                                                            (which seems to be recapitulated in this thread)

                                                                                                            1. 4

                                                                                                              Did you read the part of my message that starts ‘Edit:’, or did you only read the bit that says ‘Are you serious?’?

                                                                                                          2. 14

                                                                                                            You could try this on a project that’s not Linux, and see what happens

                                                                                                            But the Rust folks were invited, with the exact goal that they might be able to do that. They didn’t just show up and start making demands.

                                                                                                            1. 3

                                                                                                              These viewpoints are clashing:

                                                                                                              1. the static viewpoint where of course it’s a good idea to be asking about the semantics and encoding it in the type system
                                                                                                              2. the dynamic viewpoint, where this is an empirical question

                                                                                                              FWIW, if I understand correctly, I think this is a clearer explanation of what you mean by “static vs dynamic” than your previous comments over the past week have contained. I think the replies to your previous comments may have been unable to answer your question because it wasn’t clear.

                                                                                                              My reading of your previous comments was that they were unclear but seemed to be asking how usefully Rust proponents think Rust’s type system can encode properties of e.g. filesystem code (a question not specifically about Linux). My reading now is that it’s still not very clear but that you’re asking how appropriate it is for Linux to have its semantics figured out and nailed down (a question not specifically about Rust). Is that right?

                                                                                                              1. 3

                                                                                                                you’re asking how appropriate it is for Linux to have its semantics figured out and nailed down

                                                                                                                I’m not really asking that … I think the people working on it should figure it out

                                                                                                                I’m basically questioning the assumption that “kernel devs should write down the semantics in the docs, and we will translate the semantics into Rust’s static type system” is a good or workable idea

                                                                                                                And that if you disagree with that, you’re sandbagging or uncooperative

                                                                                                                It doesn’t match my experience of how large software projects are developed. I think it’s laden with assumptions that haven’t been shown to be true

                                                                                                                (I also honestly wonder what the experience of other projects was like, say Firefox. I’m happy to update based on more info. Are there concurrent protocols expressed statically in Rust in Firefox? Or how they express “legacy” C++ ownership patterns, which I imagine are many nontrivial examples of in browsers )


                                                                                                                I also question the assumption that “if we encode semantics in the static type system of Rust, then Linux will have its semantics figured out”, or the converse, which is something like “if the semantics aren’t expressible in Rust, then nobody knows what they are”

                                                                                                                I think many commenters are conflating those 2 things, and spreading FUD about the Linux kernel. (Although there are certainly good arguments/anecdotes on the other side, like the snippet about “needing to read 10 years of LKML in this thread)


                                                                                                                I brought it up again because davidalbert said essentially the same thing, though now I sorta regret it because this subthread has the same flavor as the last one

                                                                                                                Anyway, I think these are empirical questions. It seems to me that many commenters don’t. But we don’t need work that out here, since I think lobste.rs is not very relevant to Linux kernel dev :)

                                                                                                          3. 16

                                                                                                            So I basically repeat the challenge – show us it works! (not me, but the kernel community)

                                                                                                            It is a meaningless challenge without cooperative maintainers. Not in the sense that the maintainers (Ted, in this case) have to learn Rust, but in the sense that they need to properly think about and document various Linux kernel APIs. From Ted’s vehement opposition to this idea, I cannot help but think that this has never happened before, which is honestly kind of scary.

                                                                                                            And if you try to express exactly what Linux uses, it will either be impossible, or you will end up with 20 line type signatures that help nobody.

                                                                                                            You’ve been repeating this line for a while, but I’m curious if you can point to any instances of this actually happening? There have been two highly public cases so far: Wedsons presentation and Asahis GPU driver.

                                                                                                            In Wedsons case, the problem was that the API in C apparently did not have any consistent semantics, i.e. there was no correct way to use it even from C.

                                                                                                            In Asahis case the (undocumented, implicit) semantics of drm_sched caused memory safety issues in existing C code with possible kernel panics as a result. Asahi proposed a patch that would change the semantics slightly, demonstrably not break any existing C code and make it “possible” to represent the API in Rust[0] which the maintainer declined to merge.

                                                                                                            In both cases, trying to map existing but undocumented and implicit kernel APIs to Rust exposed bugs and memory safety issues in existing kernel code. Ruling out bad faith, I just cannot fathom why the existing maintainers would not embrace such an effort. They don’t even have to do any work[1], or learn Rust!

                                                                                                            In neither case has it been “impossible to represent” the existing API in Rust, and I have yet to see such a case. Please enlighten me. Otherwise, I don’t know why you keep repeating this line.

                                                                                                            Edit: In other words, please present a case where an API that is safe to use in C and has no memory safety issues, can’t or couldn’t be represented in Rust.

                                                                                                            [0]: To be clear, I don’t think Asahi is claiming that it is impossible to represent the existing API, just that it would be cumbersome, have the same memory safety issues and cause crashes in their driver.

                                                                                                            [1]: That we shouldn’t otherwise expect them to, i.e. documenting their APIs.

                                                                                                            1. 21

                                                                                                              Re [0]: All APIs can be represented in Rust since Rust is compatible with C. The question is whether and how an API can be “represented” in safe Rust, and the word “represented” is doing a lot of heavy lifting here.

                                                                                                              Some (many) APIs can be “represented” in safe Rust practically 1:1, directly encoding the semantics in the Rust type system. This is the case for APIs that don’t use pointers at all, or which only operate on an input kernel object directly, or which return a reference whose lifetime is implicitly tied to the lifetime of an input parameter, and things like that. These are the common cases.

                                                                                                              Things get more complicated with APIs that handle long-lived objects. When there are lifetime requirements for distinct long-lived objects, it is often difficult or impractical to encode that relationship in the Rust type system. In that case, we write abstractions that enforce those invariants at runtime. For example, the Rust abstraction might introduce an additional layer of reference-counting that enforces those rules dynamically. This adds some overhead but it’s often negligible. Rust makes this kind of thing easy, which is the main reason why you’d do it in Rust and not in C (in C, you need to manage refcounts manually so adding stuff like this increases the propensity for bugs. In Rust, it doesn’t). Should there really be a performance concern you could explore alternatives, but that kind of thing is rarely necessary in practice (premature optimization is not a good idea). This happened with drm_sched in one case: it requires that schedulers outlive their associated entities, which is not unreasonable. That’s easily handled by ref-counting schedulers on the Rust side and having entities hold a reference to them.

                                                                                                              Then there are APIs that are just so confusing that it’s just a mess to abstract in safe Rust, and that’s what happened with drm_sched job lifetimes: drm_sched requires that the driver guarantee that the scheduler outlives its jobs, and drm_sched itself has the scheduler take ownership of submitted jobs and manages their lifetimes, which is quite contradictory on the face of it. The actual requirement was supposed to be enforced through a convoluted set of references involving fences that screamed “someone designed one driver like this and thought it would be reasonable to require all drivers to have the same design”, and none of this was documented at all.

                                                                                                              Could I have abstracted it correctly and safely without changes? Yes, but it would have required a bunch of workaround code that would make the abstraction vastly more complicated and redundant with the scheduler itself. For example, one possible solution would have been to hold a reference to the scheduler in jobs, but that deadlocks naively, so I’d have to defer scheduler refcount drops to a workqueue, which would have required what is nominally single-threaded abstraction code to suddenly start launching asynchronous code in the abstraction to work around the issue, which feels very wrong. Plus now we’re running an extra deferred function on every job cleanup, and who knows what the performance impact of that is? Certainly more than simple refcounting. Another solution would have been to force the “driver” fences to hold the reference, but since the fence abstraction is independent of the scheduler, and the drm_sched abstraction can’t somehow add requirements to the incoming fences, the orthogonal way to do this would be to introduce another layer of fence chaining/nesting in the abstraction, again adding a big pile of complexity and duplicating things drm_sched itself already does.

                                                                                                              At this point, sure, writing a Rust abstraction without touching the C is possible but it’s impractical and clearly the wrong technical decision. Given that kernel subsystems exist to serve their consumers, and that those subsystems change all the time to support new use cases (that’s the whole point of not having a stable kernel module API!), the logical solution here is to change the subsystem. Especially in this case, where the changes needed to the C version to make it safe enough to write a safe Rust abstraction were much simpler and much less intrusive than the workarounds needed to make it work as-is in safe Rust would have been.

                                                                                                            2. 12

                                                                                                              So I basically repeat the challenge – show us it works!

                                                                                                              This is a strange challenge, because it has clearly been shown. A complex driver has been written in rust, shipped to users, and been a spectacular success (the asahi graphics driver). Another complex driver has been rewritten in rust with the intent to ship it to literally billions of users (the android binder driver).

                                                                                                              Will there be some tool that exists in the C side of the kernel that can’t be ported to rust and prevents things that need it from being written in rust? Maybe*, if so, so what? The goal is to be able to write some parts of the kernel in rust, not to port the entire kernel to rust. If a few parts can’t be ported, so be it, they (like the vast majority of existing code) can remain in C.

                                                                                                              * In truth I doubt it. I read through the RCU docs and I’d be surprised if that turned out to be particularly problematic for instance. Rust generally does quite a good job at handling concurrency primitives similar to that one.

                                                                                                              1. 1

                                                                                                                I’m talking about

                                                                                                                whether encoding huge amounts of semantics [of file system interfaces] in the type system is good idea

                                                                                                                the limitations of this idea, and whether Rust users assume it is obvious (which still seems true)

                                                                                                                NOT whether drivers have been shown to work in Rust.

                                                                                                                And this is also what the comment I replied to is talking about.

                                                                                                                1. 12

                                                                                                                  Well, sorry for misinterpreting your comment.

                                                                                                                  For what it’s worth I think you’re misreading the comment you replied to, and that it was talking about the kernel as a whole and simply using the filesystem discussion as a small topical example. Consider that it immediately precedes the part that talks about filesystems by talking about subsystems in general, and follows that up with

                                                                                                                  There’s a lot of confidence from Rust folks that Rust will obviously work in the kernel and this is just a matter of getting cooperation from recalcitrant kernel devs. I don’t think it’s that simple.


                                                                                                                  It also however seems strange to demand that rust show proof that it works for filesystems when them asking how the existing APIs work results in active hostility and a refusal to answer. No one would be able to show anything works in that environment.

                                                                                                              2. 2

                                                                                                                I think this is a reasonable guess - but at the same time I would leave it up to the R4L folks, and the actual current people writing drivers in Rust, to decide whether this fear is true or not.

                                                                                                            3. 5

                                                                                                              Thirty years ago, most programming was procedural in nature. The unit of programming was the procedure, the subroutine, the function, the algorithm.

                                                                                                              We’ve had a paradigm shift in the past two decades, partially due to formal work (e.g. Yanofsky 2014), and no longer see functions as akin to procedures, subroutines, or algorithms. This is a deliberate rhetorical conflation by the author which clashes with their later points about the power of lambda expressions.

                                                                                                              One of the conclusions that we reached was that “object” need not be a primitive notion in a programming language; one can build objects and their behavior from little more than assignable value cells and good old lambda expressions.

                                                                                                              More precisely, as previously discussed, “actor” is a type constructor and the implementation merely needs to manage mutable closures.

                                                                                                              Moreover, most of the objects in Hewitt’s theory were stateless and unchanging once created; for those, lambda expressions alone were sufficient.

                                                                                                              In the language of capability theory, particularly with E-style auditors, we say that most objects can be “deep-frozen”: transitively frozen and treated as data. The interesting nuance here is that E-style actors can consent to auditions and choose how they will be interpreted, which isn’t directly expressible with a single lambda expression but can be done with a letrec of multiple expressions.

                                                                                                              This is a deeper insight than it appears, because multiple capability-safe languages use this equivalence to simplify implementations. Monte supports E-style auditors and uses objects to implement letrecs. Nix is capability-safe and uses letrecs with lazy evaluation to implement lazy objects, with patterns like overlays.

                                                                                                              1. 5

                                                                                                                We’ve had a paradigm shift in the past two decades, partially due to formal work (e.g. Yanofsky 2014), and no longer see functions as akin to procedures, subroutines, or algorithms. This is a deliberate rhetorical conflation by the author which clashes with their later points about the power of lambda expressions.

                                                                                                                Steele invented scheme, and in Scheme what other languages might call a function was called a procedure. IIRC his philosophy was a procedure was different from a function in that it was actually executable (I want to say he talks about this in the intro of SICP).

                                                                                                                So I’m not sure he is conflating, though admittedly I have not read Yanofsky 2014 and I might not entirely understand your point.

                                                                                                                1. 2

                                                                                                                  Yanofsky 2014 merely shows that programs, algorithms, and functions are three different things, related specifically in that many programs might implement one algorithm and many algorithms might express one function. This is directly opposite the meme of functional programming, which insists that the lambda-expressions of Lisps and MLs denote functions. The paradigm shift has occurred because this meme is waning.

                                                                                                                  1. 2

                                                                                                                    (I am not well versed in this stuff.) Can you clarify how this is opposite to the meme “that expressions denote functions”?

                                                                                                                    My current guess: in the Yanofsky-type paradigm, a program is (through a choice of algorithm) an implementation (instance? model?) of a function, whereas in the meme a function is the same as an “expression” (=“program”)?

                                                                                                                    1. 1

                                                                                                                      Your guess is good, but in the presence of general recursion, it’s not enough: some programs don’t implement any function. For example, consider this Scheme expression:

                                                                                                                      (define (f x) (f x))
                                                                                                                      

                                                                                                                      Or this Haskell declaration:

                                                                                                                      f :: Integer -> Integer
                                                                                                                      f x = f x
                                                                                                                      

                                                                                                                      These don’t denote functions on the integers; if they did, then they would be defined at 0.

                                                                                                                      1. 1

                                                                                                                        These don’t denote functions on the integers; if they did, then they would be defined at 0.

                                                                                                                        I don’t understand what you mean by this. Care to elaborate?

                                                                                                                        1. 5

                                                                                                                          He’s just saying that they aren’t total functions because they never terminate.

                                                                                                                    2. 2

                                                                                                                      The abstract reads to me like Yanofsky is restating something that everyone knows in order to set the scene for the paper.

                                                                                                                      For example, I’ve got a copy of “programming language theory and its implementation” written by M J C Gordon in 1988, which says in its preface,

                                                                                                                      the functions arising in functional programming are often unlike traditional mathematical functions, and special logics, e.g. LCF, have had to be devised for reasoning about them.

                                                                                                                  2. 4

                                                                                                                    This is a deliberate rhetorical conflation by the author which clashes with their later points about the power of lambda expressions

                                                                                                                    He also seems to conflate functional programming with static types, which … I guess was kind of understandable in 2002 if you ignored Erlang, but is still a big mistake.

                                                                                                                    Another weakness of procedural and functional programming is that their viewpoint assumes a process by which “inputs” are transformed into “outputs”; there is equal concern for correctness and for termination (and proofs thereof). But as we have connected millions of computers to form the Internet and the World Wide Web, as we have caused large independent sets of state to interact–I am speaking of databases, automated sensors, mobile devices, and (most of all) people–in this highly interactive, distributed setting, the procedural and functional models have failed

                                                                                                                    Phrasing it this way about connecting millions of computers makes the omission of Erlang even more weird; Erlang fares waaaay better than Java at connecting large independent sets of state in a distributed setting!

                                                                                                                    1. 3

                                                                                                                      I guess was kind of understandable in 2002 if you ignored Erlang

                                                                                                                      Is it? I was in elementary school back then, but AIUI dynamically typed functional lisps were a thing long accepted, like elisp.

                                                                                                                      1. 5

                                                                                                                        My impression is that in the 80s and 90s lispers were still dealing with the perception that lisp was too slow to be practical, and so despite the fact that the language had support for optional functional programming, imperative programming was still quite dominant in those communities; every list operation would have a pure variant and a destructive (non-consing) variant. So having a lisp program that used immutable data structures was still seen as something of an oddity, vs Erlang where it’s a requirement. Even nowadays it’s still rare to see elisp written in a functional style.

                                                                                                                        Granted I wasn’t there; I only got into lisp in 2005. But 2002 was long before Clojure and even significantly before Racket, which is the most functional of the schemes. Outside Erlang, people who actually identified as Functional Programmers were probably working in ML dialects.

                                                                                                                      2. 2

                                                                                                                        Hmm…the World Wide Web is built out of Erlang nodes?

                                                                                                                        I was under the impression it is built from REST servers (a few of which are implemented in Erlang).

                                                                                                                        And remember that these are (extreme) position statements in a panel that’s meant to be both fun and illuminating. I think you can assume that Guy Steele has some rough idea of how functional programming works.

                                                                                                                    2. 90

                                                                                                                      I watched the video linked in the email and there’s definitely a degree of completely unwarranted hostility that would’ve prompted me to make a similar decision. I can imagine this wasn’t remotely close to the first time someone from the RustForLinux project has had to field aggressive questions arising from made up ideas about what bringing Rust into the kernel entails.

                                                                                                                      Edit: Here’s a summary of the discussion that was happening in the linked video: https://lwn.net/Articles/978738/

                                                                                                                      1. 53

                                                                                                                        I wrote large chunks of RFD 26, the document describing our thought process and our choice at Oxide to go with illumos rather than, say, Linux, for our host operating system. I recall wringing my hands for months on the subject of how likely it would be that we could work towards use of Rust in the core upstream repository of the OS, for both kernel and user mode components. Basically everybody is familiar with the stereotypes about what it’s like to work in the Linux kernel community and participate in their project spaces, and with widely shouted (if not shared!) opinions about whether it’s good to have debugging tools and safer languages. In the end I tried to give credit or at least open mindedness to the idea that perhaps the Linux folks were coming around in 2020 and 2021 and that they would have seen the light by now.

                                                                                                                        In hindsight it increasingly seems to have been a waste of good hand wringing.

                                                                                                                        1. 47

                                                                                                                          Not just hostility but an incredible degree of ignorance. Saying something like “we’ve learned from Java that methods are bad” (barely paraphrasing) is such a hilarious misunderstanding of so many concepts in programming.

                                                                                                                          1. 43

                                                                                                                            I don’t usually get angry with people on the internet. But this level of hostility and assumption of bad intent is next level. (Also, wow, looks like my corner of the internet is more friendly than I thought).

                                                                                                                            1. 38

                                                                                                                              There was absolutely zero reason for the hostility of that audience member and the conference organisers should have stepped in.

                                                                                                                              1. 20

                                                                                                                                Yeah that part shocked me as well, at the very least someone should have offered to continue the discussion offline/sidebar to allow others a chance ask questions before time. Anytime emotions start to become visible it’s passed time to step in. The speakers held their composure quite well, and I can’t imagine what kind of stress that adds on top of an already stressful event for most people (public speaking about controversial topics).

                                                                                                                                1. 3

                                                                                                                                  There was absolutely zero reason for the hostility of that audience member and the conference organisers should have stepped in.

                                                                                                                                  I would consider this to be tyrannical organizational behavior. If this actually happened I would absolutely have supported counter-organizers stepping in in order to allow Ted Ts’o to continue talking, and if that failed organizing and promoting a completely different conference run by different people in order to allow Ted Tso’ to continue making this point.

                                                                                                                                  1. 44

                                                                                                                                    The result of such approach is that arguments are won by those who shout the loudest and have the most power, not on the merits of their arguments. We have a prime example how an organisation loses contributors by defending asshole behavior. Assholes tolerate assholes, but others don’t.

                                                                                                                                    I’m an experienced Rust developer with expertise in C<>Rust interoperability, and in position where I could have been working on it professionally. There’s no way I’m going to contribute to Linux when it’s run this way.

                                                                                                                                    1. 7

                                                                                                                                      Considering working on Redox?

                                                                                                                                      I don’t contribute to any OS at the moment, but I’m considering seeing how I can help out Redox purely out of protest to this kind of circumstance. I don’t think Linux should have it’s place in the market anymore.

                                                                                                                                      1. 11

                                                                                                                                        It’s a complex situation, and the people who say Rust is a religion probably wouldn’t reflect on themselves even if Redox eclipsed their work.

                                                                                                                                        I suspect it’s more constructive to just focus on Rust’s own ecosystem and tooling (in userspace).

                                                                                                                                        1. 7

                                                                                                                                          I started looking into contributing a week or two ago and I’ve started working on a Nix-based build system for Redox, see here: https://gitlab.redox-os.org/redox-os/redox/-/issues/1552

                                                                                                                                          Seems like a small but friendly group so far.

                                                                                                                                      2. 31

                                                                                                                                        I agree the other replies, but I think this hasn’t been said clearly enough: the issue is not what Ted is saying, but how. The question is valid, though it has been rehashed a lot, but the tone and aggressiveness is not a valid way to ask a question in any context. That’s toxic behavior, plain and simple, so yes it falls within an organizer’s duty to rein in.

                                                                                                                                        1. 11

                                                                                                                                          Is the question valid? It was addressed by the speakers but he kept going. And I believe this has come up before.

                                                                                                                                          1. 9

                                                                                                                                            I meant in general it’s a valid question, I agree it sucks to bring it up then again, and shows Ted was more in it to rant than ask a good question.
                                                                                                                                            The “though it has been rehashed a lot” was meant to hint at that, but it wasn’t really the point of my comment.

                                                                                                                                        2. 30

                                                                                                                                          Have you ever been to any sort of professional conference? Talks are organised into thematic sessions, sessions have chairs, chairs keep the Q&A on track and stop things devolving like they did here, or at least encourage people not to shout over each other, like Ts’o was doing. It’s not tyranical in the least and it’s not CeNSoRsHIp!!1 either.

                                                                                                                                        3. 0

                                                                                                                                          the conference organisers should have stepped in

                                                                                                                                          Who are the organizers that they would have enough political capital to shut down Ted Ts’o?

                                                                                                                                          1. 38

                                                                                                                                            Shutting down flagrant nonsense and defending community members from abuse is one way to develop capital!

                                                                                                                                            1. 2

                                                                                                                                              Accusations of abuse are often a form of abuse, precisely because they offer an excuse for an organization to shut down something they claim is flagrant nonsense. I wouldn’t want to work with anyone who thinks that Ted Ts’o should’ve been prevented by some outside power from communicating the way he did here.

                                                                                                                                              1. 37

                                                                                                                                                What in the actual… what kind of conferences do people here go to!? Like, for me, it’s been years, and the ones I’ve attended were primarily academic conferences, but the religion comment + shouting would’ve been more than enough to make the session chair step in. Abuse or not, that kind of thing just derails the whole presentation.

                                                                                                                                                1. 22

                                                                                                                                                  I wouldn’t want to work with you either, so I think we’re all happy.

                                                                                                                                              2. 14

                                                                                                                                                The chair of a track has the full right to the room at any descent conference.

                                                                                                                                                1. 1

                                                                                                                                                  To be more clear, I don’t question whether a conference organizer could kick out a high Linux maintainer if the organizer so chose but rather whether the organizers would find it worthwhile to begin a conflict with someone who presumably has influence in the Linux dev community with which to make continued participation in that community unpleasant for the organizers (assuming the organizers are, and want to continue to be, participants in that community).

                                                                                                                                            2. 35

                                                                                                                                              Asahi Linux’s developer also recounts a similar experience. https://vt.social/@lina/113045455229442533

                                                                                                                                              1. 17

                                                                                                                                                Please tell me that wasn’t actually Ted T’so being that aggressive, as LWN suggests. I expect better from such a senior Linux contributor.

                                                                                                                                                1. 40

                                                                                                                                                  I expect better from such a senior Linux contributor.

                                                                                                                                                  You shouldn’t! This is the norm, and although some things are no longer as publicly inflammatory the attitude has been this way for literal decades.

                                                                                                                                                  1. 14

                                                                                                                                                    I don’t like to wear it as a badge of honor, but “I stood next to a lieutenant while Linus yelled at them during kernel summit” is definitely the closest I’ve ever been to the kernel development process, and it was standard practice back then whenever something new was coming to Linux. At that time, it was Kernel Mode-Setting (KMS) for GPUs.

                                                                                                                                                2. 17

                                                                                                                                                  It’s interesting that he mentions if this breaks the function of a bunch of critical file systems that users depend on, it’s not his problem.

                                                                                                                                                  I’m pretty sure that would be considered breaking userspace?

                                                                                                                                                  What’s the first rule of Linux kernel development?

                                                                                                                                                  And then his suggestion “Lets just see what happens if we don’t give a crap about the semantic interfaces in a year.”

                                                                                                                                                  Like he doesn’t know that it’s just going to be a total disaster and blow the fuck up; and claim that is evidence of the unworkability of the solution, rather than evidence of the unwillingness to even make minor changes for compatibility sake.

                                                                                                                                                  Also the comparison to Java… They are certainly suffering a lot with people just fundamentally misunderstanding what Rust is.

                                                                                                                                                  The semantic definitions I would imagine would be useful even to C programmers using C interfaces in the Linux Kernel.

                                                                                                                                                  This is a truly unfortunate development. I really hope the Rust ecosystem in the Linux Kernel continues to grow.

                                                                                                                                                  As a long time Linux kernel module developer, and current Rust developer, I’ve been following this project closely.

                                                                                                                                                  1. 8

                                                                                                                                                    It’s interesting that he mentions if this breaks the function of a bunch of critical file systems that users depend on, it’s not his problem.

                                                                                                                                                    I’m pretty sure that would be considered breaking userspace?

                                                                                                                                                    It’s not breaking user space, it’s breaking kernel space. He didn’t say that he would break file systems that end-users depend on, but rather break APIs which in-kernel users depend on.

                                                                                                                                                    This would mean breaking file systems among other things, but those breakages would be fixed before the kernel with that change is released; because Linux does not break userspace. The question is who’s responsible for fixing that, the person who made the breaking change in the API or the users of the API.

                                                                                                                                                    1. 22

                                                                                                                                                      The presenters were pretty clear that they do not expect maintainers to learn rust and that they will maintain the rust API. So that is not the question.

                                                                                                                                                      The presentation was about describing the state of their patch and clarifying how the C API actually is meant to be used. My impression was that the maintainers do not really know either:-)

                                                                                                                                                      The Asahi graphics driver dev said pretty much the same thing about the DRM layer they need to interface with… the only crashes she sees are in that layer – due to unclear and undocumented lifetime issues.

                                                                                                                                                      IMHO it would be nice to have rust wrappers for those layers: Lifetimes are clearly documented there.

                                                                                                                                                      1. 4

                                                                                                                                                        Oh I agree completely, tho Ted did problematise the “we can’t fix your Rust code when we break APIs” thing even though it was in bad faith. However I was mainly trying to delineate between “driver developer breaks their users, namely the end user, user has to adapt” and “core infrastructure breaks their users, namely drivers, driver developers have to adapt”. The former is breaking userspace, the latter is not,

                                                                                                                                                  2. 52

                                                                                                                                                    Good Lord yes, what a troubled audience member. I felt like we were about three seconds away from him shouting about a ‘goddamn WOKE AGENDA’. It must be exhausting to deal with such deep confusion combined with fearful hostility.

                                                                                                                                                    1. 22
                                                                                                                                                      1. 24

                                                                                                                                                        he worked in MIT’s Information Systems (IS) department until 1999. During this time he was project leader of the Kerberos team.

                                                                                                                                                        That’s an interesting piece of history. Kerberos remains one of the worst technologies I am forced to use on regular basis especially on non-Windows hosts.

                                                                                                                                                        1. 8

                                                                                                                                                          Kerberos remains one of the worst technologies I am forced to use on regular basis

                                                                                                                                                          Sorry I laughed. I used to work with MIT Kerberos and the GSSAPI and don’t have any fondness.

                                                                                                                                                      2. 57

                                                                                                                                                        I am not sure where you’re getting the “woke agenda” thing … that seems to be inflaming an already inflamed situation without reason. It’s a non-sequitir

                                                                                                                                                        I watched the video, and I can definitely sympathize with the author, and why an interaction like that it would prompt him to leave the project.

                                                                                                                                                        At the same time, I think the technical disagreement is fairly clear, and the social / project management disagreement is fairly clear:

                                                                                                                                                        • The Rust for Linux project wants to encode semantics of file system interfaces statically, in the Rust type system
                                                                                                                                                        • At least this particular maintainer wants to make it very clear that they are going to change the semantics of the C interfaces over time (decades), and they are not willing to fix the Rust code when he does so. And he does not think it’s realistic for every file system contributor to learn Rust.
                                                                                                                                                        • He says it’s a “pain allocation” problem

                                                                                                                                                        And he actually offers a path forward – keep doing what you’re doing, but know that we’re going to break you, and it’s up to YOU to fix that, not US.

                                                                                                                                                        He also says we will find out OVER TIME if this idea is good or not. He is not REJECTING the idea, but merely saying he refuses to do any work (and maybe even learning) to accommodate an idea that he views as experimental (or maybe even unpromising).

                                                                                                                                                        Now I have no idea if this is the right thing, because I am not involved in the kernel, and I also don’t write Rust.

                                                                                                                                                        But to me if the maintainer of a piece of code is saying this, it is actually crystal clear what the disagreement is.

                                                                                                                                                        He wants to put the burden on you to do the work, because he doesn’t see the benefit right now.


                                                                                                                                                        The Rust for Linux is making what seems like a reasonable request for more information on the semantics, so that they can encode it statically in the type system.

                                                                                                                                                        I am not sure, but I suspect the answer is “you have to figure that out yourself because there’s 30 years of history there” … or “that is a misguided way of looking at the problem – the solution does not match reality” [1]


                                                                                                                                                        I have been involved in such migrations professionally, and this is a very typical disagreement between the “old team” and a “new team”.

                                                                                                                                                        A new team assumes they are going rewrite everything and make the world better.

                                                                                                                                                        The old team has been down in the trenches for years. They have intimate knowledge of the code and the painful debugging necessary to get the system into its current state (a very successful state in this case, as Linux file systems store approximately ALL the data in the cloud, when it comes down to it)

                                                                                                                                                        The old team feels disrepected by the oversimplifications in the new way of thinking. (The perceived disrespect is probably why you’re getting this aggressive tone.)

                                                                                                                                                        A new team is genuinely optimistic and wants to improve things

                                                                                                                                                        The results are usually a mix, which is unsurprising. It’s never what the old team thinks it was, or a new team thinks it will be. It is a very typical conflict.

                                                                                                                                                        (And note it’s also possible that there are multiple new teams, and that one or more new teams is abandoned. But that doesn’t mean it’s not worth trying.)


                                                                                                                                                        It has nothing to do with any “woke agenda”. Do you agree? If so, I suggest retracting this comment, because it’s unhelpful and inaccurate

                                                                                                                                                        1. 73

                                                                                                                                                          To me, the issue with what he said has nothing to do with the technical content and everything to do with the hostility. It sounded like he was seething with hatred toward the language and the Linux Rust project. Hell, he even described the speaker as pushing a religion!

                                                                                                                                                          It was not a comment from someone trying to productively discuss technical challenges.

                                                                                                                                                          1. 29

                                                                                                                                                            To me, the issue with what he said has nothing to do with the technical content and everything to do with the hostility. It sounded like he was seething with hatred toward the language and the Linux Rust project. Hell, he even described the speaker as pushing a religion!

                                                                                                                                                            The discussion was about power, really, disguised as technical one. It’s about establishing who is subservient to whom: the Rust interfaces to C ones, or vice versa.

                                                                                                                                                            1. 16

                                                                                                                                                              Yes, in the context of the Linux project. The people who have power are the ones who have made things work for users, and Linux has a track record of making things work.

                                                                                                                                                              Are there Rust devs interested in contributing to GNU Hurd, and converting it to Rust? (honest question)

                                                                                                                                                              If Rust devs make the kernel better, and I hope they do, then they will naturally have more power. But so far it looks like it’s still the early days.


                                                                                                                                                              Rust developers can fork Linux and do whatever they want with it – that is the beauty of open source. There can be parallel development among people who disagree.

                                                                                                                                                              Users can vote with their feet

                                                                                                                                                              I actually suspect that is the best solution here – as I would personally like a memory safe kernel, but I’m not sure if Rust is on the path to it. It would let both projects move faster.

                                                                                                                                                              Ted Tso is a long time maintainer and he’s basically saying he refuses to merge stuff which is going to make his job harder later.

                                                                                                                                                              1. 43

                                                                                                                                                                That’s not what I heard. Ted said that he isn’t interested in learning anything about Rust, even if it makes his job easier later. It’s about anti-intellectualism and machismo, not about maintenance burdens.

                                                                                                                                                                1. 10

                                                                                                                                                                  He has not yet been sold on the values of Rust in projects of the scope of the Linux kernel.

                                                                                                                                                                  At such a time as he is convinced, he will probably change his mind on what he wishes to learn.

                                                                                                                                                                  This isn’t anti-intellectualism. This is pragmatism.

                                                                                                                                                                  1. 55

                                                                                                                                                                    Ted clearly isn’t listening to what the presenter is saying. Ted says “I don’t want to fix Rust code when it breaks because we change the C API” and the presenter says “that’s fine, I’ll fix the Rust code, but please tell me what the current semantics of the C API are”, to which Ted says “I don’t want to learn Rust!”.

                                                                                                                                                                    1. 16

                                                                                                                                                                      Pragmatism would be delegating the work to someone else. This isn’t pragmatism, it’s childishness.

                                                                                                                                                                      1. 7

                                                                                                                                                                        Right, and learning Rust deeply enough only to be able to make such a decision might feel like putting the cart before the horse to him.

                                                                                                                                                                    2. 13

                                                                                                                                                                      Are there Rust devs interested in contributing to GNU Hurd, and converting it to Rust? (honest question)

                                                                                                                                                                      Not really. I’ve answered a few questions like this on the Phoronix Forums, but basically:

                                                                                                                                                                      1. HURD is dead, has no usecase or userbase.
                                                                                                                                                                      2. Porting Rust to it would be significantly more difficult than simply starting from scratch.

                                                                                                                                                                      Linux is a very special case because it’s used everywhere, it’s the standard OS of the world, even MS has given up on Windows and is just letting everyone use Linux now (through WSL or Azure Linux). There are a lot of reasons to use Rust, but the primary benefits are a more secure kernel and it will bring in new developers, as there are a lot less new C developers than there used to be.

                                                                                                                                                                      I’ve considered the implications of making a separate fork of Linux just for Rust, but I don’t think it’s feasible. I can’t see a bunch of people just going over to some random fork that has no funding, and the split would be detrimental for both projects, but especially the fork as they’ll slowly lose the ability to merge patches as they fundamentally change how Linux is architected.

                                                                                                                                                                      1. 8

                                                                                                                                                                        Rust developers can fork Linux and do whatever they want with it – that is the beauty of open source.

                                                                                                                                                                        They have. The Asahi Linux GPU drivers are all in Rust in their own fork.

                                                                                                                                                                        1. 4

                                                                                                                                                                          I actually suspect that is the best solution here – as I would personally like a memory safe kernel

                                                                                                                                                                          It’s a side-note but I wish people would stop using “memory safe” in reference to programs to mean “written in a memory-safe language” and not “free of memory errors”, which is what it is (or at least was) actually supposed to mean (of course the first implies the second, but the reverse is not true). The use of unsafe as an actual keyword in Rust hasn’t helped the situation; “unsafe Rust” can mean so many things depending on the context (an unsafe language subset superset, or a piece of code that is only valid in that subset, or a piece of code written in that subset that also has a memory safety issue, or code within an unsafe block regardless of whether it uses unsafe language constructs) and it causes so much confusion in discussions about memory safety.

                                                                                                                                                                          I think what you are saying is that you like the idea of a kernel written in a memory-safe language, not just that you want a kernel free of memory safety errors, which should really be a given.

                                                                                                                                                                          1. 8

                                                                                                                                                                            I want a kernel that’s free of memory safety errors [1], not necessarily one that’s written in Rust or any other particular language

                                                                                                                                                                            Rust is one promising solution, but not the only possible solution

                                                                                                                                                                            [1] and one that’s free of logical errors like missing/incorrect access checks, local root exploits, etc.

                                                                                                                                                                            1. 5

                                                                                                                                                                              I think this might be where the ‘religion’ word came from. I don’t see other languages aggressively pushing rewrites for everything. Video said “Rust has ADTs” which weren’t invented in Rust, nor exclusive to Rust, nor popularized by Rust. Same applies to memory safety, and other arguments used in the ‘why Rust’—but also in the Venn diagram of the languages that are suitable for systems programming is Rust not alone or particularly remarkable.

                                                                                                                                                                              1. 23

                                                                                                                                                                                Other languages with Rust’s features aren’t suitable for integration into the Linux codebase.

                                                                                                                                                                                • OCaml, Haskell, etc compile to native code, but have large runtimes and need a lot of tooling for even basic C interop. It’s difficult for a human to predict the machine code emitted by their compilers.
                                                                                                                                                                                • Go is memory-safe but is missing a lot of features that are considered useful for writing highly-reliable code, and its development roadmap isn’t easily changed by outside contributors. Support for compilation to non-hosted targets is via a third-party project (TinyGo).
                                                                                                                                                                                • Zig, Odin, Carbon, etc aren’t mature enough yet.
                                                                                                                                                                                • Ada, D, Vala, and various other languages over the years have had their chance and have largely failed to gain mindshare outside of a few niche areas.

                                                                                                                                                                                Rust is the first successful attempt to write a language that solves the same problems as C and also has the sort of nice features that application programmers have had for twenty years. Of course people would be excited about it.

                                                                                                                                                                                1. 17

                                                                                                                                                                                  Zig is not memory safe language.

                                                                                                                                                                                  1. 16

                                                                                                                                                                                    Go is memory-safe but is missing a lot of features that are considered useful for writing highly-reliable code, and its development roadmap isn’t easily changed by outside contributors. Support for compilation to non-hosted targets is via a third-party project (TinyGo).

                                                                                                                                                                                    Go is not memory safe in the presence of multiple threads.

                                                                                                                                                                                    Zig, Odin, Carbon, etc aren’t mature enough yet.

                                                                                                                                                                                    None of these are memory safe, nor will they ever be.

                                                                                                                                                                                    1. 5

                                                                                                                                                                                      Go is not memory safe in the presence of multiple threads.

                                                                                                                                                                                      Yep. Started a Go job recently after five years of rust. My heart sank the first time I saw “make sure not to call this without holding a mutex!” in some function’s comments.

                                                                                                                                                                                      1. 3

                                                                                                                                                                                        Thats not traditionally what memory safety means. Traditionally memory safety means something more like free from memory errors that would lead to control of the instruction pointer which removes a massive class of never ending security vulns. Go achieves this.

                                                                                                                                                                                        Crashing from threads racing to overwrite a variable could definitely be considered a safety issue in some domains of course.But, If you redefine memory safety this way, doesn’t that exclude all languages but rust?

                                                                                                                                                                                        1. 14

                                                                                                                                                                                          Go does not achieve this.

                                                                                                                                                                                          In Go, stores to slice-type variables are not atomic. You can create three goroutines that all have access to a struct that has a slice as one of its fields:

                                                                                                                                                                                          Goroutine one stores a small slice to the field, in a loop.

                                                                                                                                                                                          Goroutine two stores a large slice to the field, in a loop.

                                                                                                                                                                                          Goroutine three reads the field until it gets the base of the small slice and the length of the last one. From there, you can build type confusion, use-after-free, and all other categories of memory safety bugs. You can overwrite a function pointer (or interface type) with a value that you control and cause control flow to transition to n arbitrary point.

                                                                                                                                                                                          Crashing from threads racing to overwrite a variable could definitely be considered a safety issue in some domains of course.But, If you redefine memory safety this way, doesn’t that exclude all languages but rust?

                                                                                                                                                                                          No, this is something that doesn’t happen in any memory-safe language. Nothing in the JVM or CLR has this problem, neither do Haskell, ML, Lisp, JavaScript, Erlang, and so on.

                                                                                                                                                                                          Memory safe means that every memory access must be via a valid pointer that is derived from a pointer to a valid object (global, heap, or stack allocation), is within the bounds of that object, and is within the lifetime of that object. Any access that does not follow these rules must either trap at run time or be disallowed at compile time. It is a subset of type safety, which additionally imposes rules on the operations within an object.

                                                                                                                                                                                          1. 1

                                                                                                                                                                                            In Go, stores to slice-type variables are not atomic

                                                                                                                                                                                            Super interesting. Would it break backwards compatibility to fix this?

                                                                                                                                                                                            1. 4

                                                                                                                                                                                              No, it would be an ABI change and Go doesn’t guarantee a stable ABI. It would be a perf hit though. Almost no CPUs can do atomic three-word stores, so you’d need to either hold a lock while updating slices or do what .NET did and make slices heap-allocated things. This places more strain on the GC.

                                                                                                                                                                                            2. 1

                                                                                                                                                                                              I realize this is possible: https://blog.stalkr.net/2015/04/golang-data-races-to-break-memory-safety.html

                                                                                                                                                                                              But, I still argue that Go is considered a memory-safe language by normal definitions. I have never seen a single real-world Go bug of this nature that could be used as a security vuln which brings it out of the class of languages like C/C++ for which large code bases seem to have a never ending problem of bugs and security vulns from being memory-unsafe.

                                                                                                                                                                                            3. 3

                                                                                                                                                                                              Crashing from threads racing to overwrite a variable could definitely be considered a safety issue in some domains of course.But, If you redefine memory safety this way, doesn’t that exclude all languages but rust?

                                                                                                                                                                                              I think at the very least it would also exclude BEAM languages, where nothing is shared?

                                                                                                                                                                                          2. 5

                                                                                                                                                                                            OCaml, Haskell, etc compile to native code, but have large runtimes and need a lot of tooling for even basic C interop. It’s difficult for a human to predict the machine code emitted by their compilers.

                                                                                                                                                                                            OCaml has a moderate runtime. I wouldn’t call it ‘large’. The MirageOS unikernel is written in OCaml and Mirage programs are very small and start up in a handful of milliseconds. Also I wouldn’t say it needs ‘a lot of tooling’ for basic C interop, it supports C FFI out of the box. Finally, OCaml is widely recognized as generating quite predictable Assembly.

                                                                                                                                                                                            I think all your points do hold for Haskell, though.

                                                                                                                                                                                            1. 2

                                                                                                                                                                                              One point on OCaml, aren’t they looking to deprecate 32 bit support? Probably wouldn’t be suitable for Linux.

                                                                                                                                                                                              1. 2

                                                                                                                                                                                                They have removed 32-bit support from OCaml 5 onwards, but the latest 4.14.x series is still supported. And Linux might remove 32-bit support in the near-to-mid future: https://www.reddit.com/r/linux/comments/152yeqx/there_are_plans_to_drop_32bit_support_from_the/

                                                                                                                                                                                                1. 2

                                                                                                                                                                                                  One random maintainer opining that they should remove 32 bit support is not indicative of much.

                                                                                                                                                                                                  but the latest 4.14.x series is still supported.

                                                                                                                                                                                                  Will it be supported 20 years from now? We are talking about integration into the Linux kernel, after all.

                                                                                                                                                                                                  1. 1

                                                                                                                                                                                                    Will Linux support 32-bit 20 years from now?

                                                                                                                                                                                                    1. 1

                                                                                                                                                                                                      At most the syscall ABI. Maybe redirected binfmt style to 2030’s kernel running in a special VM (points at WSL).

                                                                                                                                                                                                      1. 1

                                                                                                                                                                                                        Yes, because the cheapest processor nodes are not getting any smaller, so the silicon cost savings of 32 bit over 64 bit will continue to make sense forever. Linux will only lose 32 bit support if people decide to just stop using Linux for small systems.

                                                                                                                                                                                                        1. 1

                                                                                                                                                                                                          If the cost savings are substantial enough then I’m sure someone will step up and pay to maintain OCaml 32-bit support. It shouldn’t be that difficult since the support already exists in the 4.14.x series, the last series before 5.x (multicore) 🤷‍♂️

                                                                                                                                                                                              2. 3

                                                                                                                                                                                                “First successful” implies other attempts didn’t reach that goal & they have, but community uptake & such are a fickle bit that can get a “aren’t mature enough yet” aren’t despite having sound fundamentals, but even some are quite old/mature/stable, just not a lot of users even if they, say, have a more robust type system than Rust’s affine types which has limitations (such as linear types). One other difference is unless exposing externs for C binding, Rust’s ABI isn’t stable or particularly usable/portable outside of Rust which continues to fuel the rewrite it all in Rust with Rust libs situation as opposed to the C libs that back so many projects regardless of language. If Rust was as easy to use/link from every language as C, then I would be more enthusiastic about it as a step in the right direction even with type system limitations, but as the post above me mentioned, it is not the only language that could be a solution to this problem.

                                                                                                                                                                                                1. 14

                                                                                                                                                                                                  Which non-Rust language do you think should be used for writing memory-safe code in the Linux kernel?

                                                                                                                                                                                                  One other difference is unless exposing externs for C binding, Rust’s ABI isn’t stable or particularly usable/portable outside of Rust

                                                                                                                                                                                                  I think you’re mixing up a couple issues.

                                                                                                                                                                                                  The C ABI is widely used because any language with the concepts of function calls and memory access can use it. It’s common ground for any language that compiles to native code, but that also means it’s not idiomatic in any of the languages that are using it for FFI. Even in C++, which has the smoothest possible upgrade path from C, you’ll need an extern "C" layer of plain functions wrapping your classes and templates.

                                                                                                                                                                                                  Whether or not Rust has a stable ABI for its own semantics doesn’t matter for cross-language use cases. The reason to want a stable ABI is better support for pre-compiled object code archives, which is pretty niche in the use cases that Rust is focused on.

                                                                                                                                                                                                  Rust’s ABI isn’t stable or particularly usable/portable outside of Rust which continues to fuel the rewrite it all in Rust with Rust libs situation

                                                                                                                                                                                                  The push to rewrite existing code in a memory-safe language is because people are tired of having their programs and computers crash, or get taken over by botnets, or get all their tax documents encrypted.

                                                                                                                                                                                                  It’s not about Rust. Rust is probably the least-popular memory-safe language in common use today. All the Rust code in the world is a fraction of a percent of the C#, Swift, Java, and JavaScript code out there – and that code has almost entirely displaced C/C++ for the development of applications.

                                                                                                                                                                                                  The reason people object to Rust isn’t because of anything about Rust, it’s because because they want to use C forever, and they hate the idea of seeing the last remnants of the PDP-11 era get scoured away down the drain.

                                                                                                                                                                                                  If Rust was as easy to use/link from every language as C, then I would be more enthusiastic about it as a step in the right direction

                                                                                                                                                                                                  Rust is as easy to use/link from every language as C – easier in some ways, because you don’t have to worry about dynamic symbol compatibility in libc. The rustc output is a regular object file that can be passed into the regular build toolchain, and a shared library written in Rust can be a drop-in replacement for one in C.

                                                                                                                                                                                                  1. 4

                                                                                                                                                                                                    Which non-Rust language do you think should be used for writing memory-safe code in the Linux kernel?

                                                                                                                                                                                                    If it were gun to my head (meaning developer ecosystem/community isn’t there even if it is an old language), I would pick ATS as a ‘C generator’ for supporting linear types for tracking resources over Rust’s affine types–along with having refinement + dependent types & a proof system you could actually start asserting things in the type system beyond Rust’s type system & language features capabilities (including tail call optimization as jumps) while having all the low-level resource allocations + tracking (memory alloc, shared memory, locks, pointers, etc.). The type system asserts + zero-cost abstractions can eliminate most run time checking, and being from the ML family tree (which technically Rust came from OCaml explaining many of its features), you have a syntax, if unfamiliar to the C programmer, that is more ergonomic for doing ADTs/pattern matching & recursion. The compiler is built around abstracting over & even outputting C code to be linked via C code so it doesn’t disrupt those still wanting to use C or where C is easier.

                                                                                                                                                                                                    But this would likely never happen & be even less popular of an option even if I think it is neat & crosses all the boxes.

                                                                                                                                                                                                  2. 4

                                                                                                                                                                                                    You may be interested in the proposed crABI ABI, which has as a goal the ability to interop with other languages in a richer way than simply exposing C types.

                                                                                                                                                                                                    but as the post above me mentioned, it is not the only language that could be a solution to this problem.

                                                                                                                                                                                                    There are languages in development that could do the job of Rust here, none of which I think have been mentioned in this thread, but they’re all way less mature than Rust. All languages in existence that may be mature enough are simply inadequate.

                                                                                                                                                                                                2. 4

                                                                                                                                                                                                  I think this might be where the ‘religion’ word came from. I don’t see other languages aggressively pushing rewrites for everything.

                                                                                                                                                                                                  All popular languages with a young and enthusiastic user base ask for projects to be rewritten in their language of choice.

                                                                                                                                                                                                  The C++ crowd famously nagged Linus to use C++ in the kernel till he told them very explicitly he does not want to. And evenntoday youbget people arguing for C++ in the kernel in addition to or instead of rust. The kernel got by pretty well as there are not too many languages that fit its niche, applications get this a lot more.

                                                                                                                                                                                                  1. 1

                                                                                                                                                                                                    I was going to say that the user base was the only truly exceptional bit, but being non-technical & might be just zeitgeist (we will see) I left it out :)

                                                                                                                                                                                              3. 7

                                                                                                                                                                                                I want a memory-safe kernel, which definitionally means a kernel written primarily in a memory-safe language.

                                                                                                                                                                                                There do exist kernels written in memory-unsafe languages that, when compiled to a binary artifact with a specific toolchain, can be proven to contain no memory safety errors. But those kernels have extremely high development overhead due to all the extra manual verification. Consequently they do not, and likely never will, have the breadth of hardware and software support needed to supplant Windows / macOS / Linux as the foundation layer of all general-purpose computing.

                                                                                                                                                                                                “unsafe Rust” can mean so many things depending on the context (an unsafe language subset superset, or a piece of code that is only valid in that subset, or a piece of code written in that subset that also has a memory safety issue, or code within an unsafe block regardless of whether it uses unsafe language constructs)

                                                                                                                                                                                                I think you’ve got this wrong – “unsafe Rust” has a single definition[0]. When discussing code that contains memory safety errors, Rust programmers use terms such as “unsound” (or “incorrect”, “buggy”, “fucking broken bullshit”, etc depending on mood) to describe code that contains memory safety errors.

                                                                                                                                                                                                Being unsafe doesn’t mean that the code contains memory safety errors, it means that the code can’t be proven memory-safe by the compiler.

                                                                                                                                                                                                [0] To the extent that any programming language name does. It’s true that programming language names are usually used for both the language itself and code written in that language (e.g. “a new version of Java was released” and “I don’t want to read ten thousand lines of Java”), but that’s not Rust-specific.

                                                                                                                                                                                                1. 4

                                                                                                                                                                                                  I want a memory-safe kernel, which definitionally means a kernel written primarily in a memory-safe language.

                                                                                                                                                                                                  It doesn’t though, that was the whole point I was making.

                                                                                                                                                                                                  I think you’ve got this wrong – “unsafe Rust” has a single definition

                                                                                                                                                                                                  It might have a single formal definition (where?), but it is “casually” used in all the ways I pointed out.

                                                                                                                                                                                                  When discussing code that contains memory safety errors, Rust programmers use terms such as […]

                                                                                                                                                                                                  Yes, that’s the problem. They can’t call it “unsafe”, which is what would’ve been said prior to the existence of Rust, because it has become ambiguous.

                                                                                                                                                                                                  Being unsafe doesn’t mean that the code contains memory safety errors

                                                                                                                                                                                                  I spoke of programs, not of smaller pieces of code, for which I don’t think there’s necessarily any prevalent definition of “unsafe”. But for programs, being unsafe definitely does or at least did mean that the program (code) contains a memory safety error. It’s only since the emergence of Rust (and its growing popularity) that this definition has become muddied.

                                                                                                                                                                                                  You’re unintentionally reinforcing my point - that the use of “unsafe” as a keyword in Rust has led to confusion about what a “memory-unsafe program” actually is.

                                                                                                                                                                                                  1. 7

                                                                                                                                                                                                    But for programs, being unsafe definitely does or at least did mean that the program (code) contains a memory safety error. It’s only since the emergence of Rust (and its growing popularity) that this definition has become muddied.

                                                                                                                                                                                                    I disagree with both assertions. The term “unsafe” in programming has always described code that may contain errors, because if the code is known to contain an error then it’s simply incorrect.

                                                                                                                                                                                                    I know from personal experience that the use of “unsafe” to describe programming languages without memory-safety guarantees dates to at least the mid ‘90s (when it featured prominently in arguments about Sun’s Java applets vs Microsoft’s ActiveX vs Macromedia’s Flash), and would not be surprised if more experienced devs could cite examples from the Usenet era.

                                                                                                                                                                                                    Rust introduced the concept of memory safety to a generation of systems programmers who grew up after C had conclusively trounced all of its competitors, but that doesn’t mean Rust originated the idea.

                                                                                                                                                                                                    1. 5

                                                                                                                                                                                                      I disagree with both assertions. The term “unsafe” in programming has always described code that may contain errors, because if the code is known to contain an error then it’s simply incorrect.

                                                                                                                                                                                                      Here’s a 2009 paper discussing memory safety as a property of a C program: safe if it contains no memory errors, unsafe otherwise:

                                                                                                                                                                                                      https://link.springer.com/chapter/10.1007/978-3-642-04694-0_10

                                                                                                                                                                                                      An important research question is thus the following: Given a program written in an unsafe programming language like C, how can one guarantee that any execution of this program is memory-safe?

                                                                                                                                                                                                      Here it’s talking about specific executions being safe or unsafe, and here:

                                                                                                                                                                                                      For instance, CCured [7] uses pointer annotations and analyzes the source of the program, trying to prove it memory safe

                                                                                                                                                                                                      It’s talking about proving the memory safety of a program (though it’s not written in a memory-safe language).

                                                                                                                                                                                                      This spells it out very clearly:

                                                                                                                                                                                                      This paper makes a first step towards bridging this gap, by introducing a formal definition of memory safety for programs written in a non-memory safe programming language and execution platform

                                                                                                                                                                                                      So, it’s certainly not true that:

                                                                                                                                                                                                      “unsafe” in programming has always described code that may contain errors

                                                                                                                                                                                                      At least this one paper is an exception to that claim. I’m sure there are plenty of others, if you are willing to search.

                                                                                                                                                                                                      Here’s a 2014 blog post by Michael Hicks, a professor of Computer Science at the University of Maryland:

                                                                                                                                                                                                      http://www.pl-enthusiast.net/2014/07/21/memory-safety/

                                                                                                                                                                                                      For the purposes of this post, we are generally considering whether a program execution is memory safe or not. From this notion, we deem a program to be memory safe if it all of its possible executions are memory safe, and a language to be memory safe if all possible programs in the language are memory safe.

                                                                                                                                                                                                      That’s a pretty clear definition, in line with what I’ve stated and not equivalent to your own definition. A memory-safe language can only be used to write memory-safe programs, but that doesn’t mean that all memory-safe programs are written in memory-safe languages.

                                                                                                                                                                                                      I know from personal experience that the use of “unsafe” to describe programming languages without memory-safety guarantees dates to at least the mid ‘90s

                                                                                                                                                                                                      The use of “safe” or “unsafe” to describe programming languages isn’t at question.

                                                                                                                                                                                                      1. 6

                                                                                                                                                                                                        I agree with both davmac and jmillikin.

                                                                                                                                                                                                        • Everyone agrees that for languages, the natural definition of being “memory safe” is that no program has memory errors. (In practice we use a more complex, less natural definition, closer to “a language that pushes you towards writing programs mostly with this property and with clear social contracts about the exceptions”) Same with programs, a program is “memory safe” if no run of the program has a memory error. This is consistent with Mike Hicks’ terminology, which is fairly clear.

                                                                                                                                                                                                        • Obviously “not safe” is the negation of “safe”, so a language is “not memory-safe” if some of its programs have memory errors, and a program is “not memory-safe” if some of its runs/executions have memory errors.

                                                                                                                                                                                                        • We probably want “unsafe” to mean the same thing as “not safe” because doing something different would be confusing. (But not unheard of.) So we want to define an “unsafe” program as a program that has some runs that have memory errors, which is consistent with what davmac claims but appears contradictory to what jmillikin’s claim.

                                                                                                                                                                                                        • But note that jmillikin is talking about what “unsafe” means in Rust, and unsafe is first a qualifier of program fragments, not whole programs. A natural definition of “memory safe” for a program fragment is something like: for any usage of this fragment in a program that “has no other source of unsafety”, the program is memory safe. (This is a bit tricky and not obvious to define formally, but programming language researchers are good at this.) Say a function, for example (but it also works for language constructs, etc.), is memory-safe in this sense if there isn’t a way to get a memory error by calling it.

                                                                                                                                                                                                        • I believe that this notion of safety of a program fragment is consistent with the established use of “memory safe” in industry and academia. It is compatible with the claims of jmillikin, and also with the formal statements of Mike Hicks cited by davmac. In OCaml, we have a function Array.unsafe_get : 'a array -> int -> 'a, which is not memory-safe as it does not perform bound-checking on the array access; this is “unsafe” precisely in this sense – and has been around well before Rust was introduced.

                                                                                                                                                                                                        Now one thing that is a bit confusing is that there are several reasonable but incompatible definitions of what it means for a program to be “unsafe”. The academic citations from davmac write that a program is unsafe if some of its executions contain memory errors. Another usage that exists in the wild (I believe well before Rust, but maybe Rust popularized it) is to say that a program is “unsafe” if it contains “unsafe” fragments. I believe that the first definition makes more sense if we think of the program extensionally, as an abstract object that runs, and that the second definition makes sense if we think of the program intentionally, mostly as source code (that can be executed).

                                                                                                                                                                                                        1. 1

                                                                                                                                                                                                          I appreciate that you’re trying to engage in this discussion in good faith. I do need to point out though:

                                                                                                                                                                                                          But note that jmillikin is talking about what “unsafe” means in Rust

                                                                                                                                                                                                          That is exactly the issue I was raising right off the bat - the terminology introduced by Rust has muddied the more general, previously-existing terminology about memory-safe programs. jmilkin rejected that assertion, though; so, if their ongoing argument was actually about a different “unsafe” that is specific to Rust, then that would accord with my point, that the terminology has become confused.

                                                                                                                                                                                                          And also:

                                                                                                                                                                                                          The academic citations from davmac write that a program is unsafe if some of its executions contain memory errors.

                                                                                                                                                                                                          Indeed, but the only reason that I only cited academic sources because those were the ones that I could find that could easily be dated to a pre-Rust-prevalance period. There are plenty of non-academic uses of “memory safe” entailing the exact same definition. I won’t point them out because I’m not a personal assistant and people should be able to do their own Google searches. After pointing out the academic cases, jmilkin shifted the goalposts by dismissing them as being only relevant to an “academic bubble”. Their response was so arrogant and condescending that I posted a snarky reply (that I partially regret, but which frankly was deserved) designed to close off the conversation. The fact is that uses of those definitions can easily be found, today, outside of any “academic bubble”, but it’s not my job to provide counterexamples to every bad argument that is made against something I’ve said. People can believe what they want, even if it’s wrong, or do a tiny bit of groundwork and find out for themselves.

                                                                                                                                                                                                          Now one thing that is a bit confusing is that there are several reasonable but incompatible definitions of what it means for a program to be “unsafe” […] Another usage that exists in the wild (I believe well before Rust, but maybe Rust popularized it) is to say that a program is “unsafe” if it contains “unsafe” fragments.

                                                                                                                                                                                                          The way I understood it was clear enough, and the quotes I did provide illustrate some nice concise definitions which matched that understanding. While indeed these don’t prove that other definitions weren’t used, they do clearly disprove jmilkin’s sweeping statement:

                                                                                                                                                                                                          “unsafe” in programming has always described code that may contain errors
                                                                                                                                                                                                          

                                                                                                                                                                                                          I think, if there’s going to be any argument about what definitions were around and when, they need to be based on more than just bold assertions that are clearly contradicted by available evidence. Your observation about Array.unsafe_get is at least a starting point in that regard (although it doesn’t prove anything by itself, of course).

                                                                                                                                                                                                        2. 6

                                                                                                                                                                                                          It’s possible that some areas of academia use non-standard terminology, in the same way that astrophysics describes all elements heavier than helium as “metallic”. I don’t think that matters to anyone outside that specific academic bubble.

                                                                                                                                                                                                          1. 5

                                                                                                                                                                                                            It’s possible that some areas of academia use non-standard terminology

                                                                                                                                                                                                            It’s also possible that terminology originates in some area of academia, and is used somewhat consistently outside of that area until some popular phenomenon - say, the emergence of a new programming language - leads to it entering the lexicon of a broader population, and beginning to be misused by a segment of that population who don’t realise that they are overloading the term by using it a slightly different context, for example.

                                                                                                                                                                                                            I don’t know if that’s how it actually happened, but it’s certainly possible, and since we’re just apparently throwing possibilities out there now, may as well throw that one out too right?

                                                                                                                                                                                                            That you don’t think it matters to anyone isn’t of any concern to me or anyone else that it does matter to, sorry.

                                                                                                                                                                                                    2. 3

                                                                                                                                                                                                      I feel like your definition of unsafe in Rust is a bit nebulous. I have a better one: Rust guarantees that it will have no undefined behavior (there’s one or two places it doesn’t, but those are known bugs.) Rust also has a few built-in APIs to perform actions which can lead to undefined behavior (operations outside of the purview of the compiler), these APIs are manually marked as unsafe so that they can only be used in other unsafe (allows UB) scopes.

                                                                                                                                                                                                      This is what people mean when they say Rust is safer than C because C is basically Rust in an entire unsafe context, because C itself allows UB, whereas Rust doesn’t. It’s a matter of UB.

                                                                                                                                                                                                      1. 3

                                                                                                                                                                                                        The question being discussed in this thread isn’t the exact types of behavior that are forbidden outside of unsafe { ... } blocks, it’s the definition of “unsafe” itself.

                                                                                                                                                                                                        davmac wants “unsafe” to refer to a property of the program as a whole. In this definition if a program can reach a state that permits it to execute instructions that violate the safety guarantees of the language, then the program is “unsafe”. In this model it doesn’t make sense to describe a function (or module, or library) as safe or unsafe – safety can only be verified given a full execution graph. And if someone says a program is unsafe, they’re not saying it might contain an error, they’re claiming that it does contain an error.

                                                                                                                                                                                                        Furthermore, he wants to define “memory-safe language” to mean a language that can only express memory-safe programs. In other words, if it’s possible to write a program that can violate memory-safety guarantees, then he would say that the language that program is written in is not memory-safe.

                                                                                                                                                                                                        Thus he claims that Rust is not a memory-safe language – and presumably none of Java, C#, Haskell, Python, Ada, or JavaScript are either. I’m honestly not sure whether there are any languages he would consider memory-safe. It strikes me as the conversational equivalent of setting off a fart bomb in a theater.

                                                                                                                                                                                                        1. 2

                                                                                                                                                                                                          davmac wants “unsafe” to refer to a property of the program as a whole. In this definition if a program can reach a state that permits it to execute instructions that violate the safety guarantees of the language, then the program is “unsafe”

                                                                                                                                                                                                          I’m sorry, but you’re confused. It’s not that I want “unsafe” to mean anything in particular, it’s that I believe it does mean something in particular. But not what you are claiming here; in the previously established meaning, “unsafe” has meaning outside of languages that don’t provide any safety guarantees.

                                                                                                                                                                                                          Thus he claims that Rust is not a memory-safe language

                                                                                                                                                                                                          What? I didn’t claim that. (Unless perhaps… if you mean “Rust including unsafe Rust” then … well, if you want to argue that “Rust including unsafe Rust is a memory safe language”, go at it, I won’t try to stop you).

                                                                                                                                                                                                          It strikes me as the conversational equivalent of setting off a fart bomb in a theater.

                                                                                                                                                                                                          I don’t see how, though that seems like almost an appropriate response to the ridiculous claims you’re making here now.

                                                                                                                                                                                                          1. 4

                                                                                                                                                                                                            Thus he claims that Rust is not a memory-safe language

                                                                                                                                                                                                            What? I didn’t claim that.

                                                                                                                                                                                                            Using the definition “memory-safe language” as a language for which all valid programs obey the language’s memory safety guarantees, then a language cannot be memory safe if it (1) has some concept of memory mutability or visibility, (2) supports Linux as an execution platform, and (3) is able to perform file I/O on arbitrary paths.

                                                                                                                                                                                                            Rust distinguishes mutable and immutable memory regions, supports Linux as a target platform, and is able to perform file I/O. Therefore, it’s possible to define a program entirely in safe Rust that modifies its own memory via /proc/self/mem, and therefore the program is unsafe, and (per the claimed definition) safe Rust is unsafe.

                                                                                                                                                                                                            I don’t see the value in such a definition, since all of the languages of interest to industry would be excluded from the “safe” category, so I follow the standard definition of memory-safety as applied to both source code (not programs) and programming languages.

                                                                                                                                                                                                            1. 3

                                                                                                                                                                                                              Using the definition “memory-safe language” as a language for which all valid programs obey the language’s memory safety guarantees

                                                                                                                                                                                                              That wasn’t the definition, read it again. It’s not about violating or not violating the “language’s memory safety guarantees” (if it was, it would be meaningless for languages which don’t provide such guarantees).

                                                                                                                                                                                                    3. 3

                                                                                                                                                                                                      And for that matter, I wish that people would stop calling any old language which bolts memory-safe constructs onto conventional pointer arithmetic but leaves the latter exposed to unskilled programmers “memory safe”.

                                                                                                                                                                                                  2. 2

                                                                                                                                                                                                    There’s no reason in principle why those should be mutually-exclusive.

                                                                                                                                                                                                  3. 8

                                                                                                                                                                                                    Interestingly, to me it sounded like a disagreement between experience and inexperience. I have conflated experience with hostility and/or authority many times in the past.

                                                                                                                                                                                                    EDIT: @andyc said it way better than I could!

                                                                                                                                                                                                    1. 18

                                                                                                                                                                                                      The “you’re pushing a religion” part invalidates that interpretation in my opinion.

                                                                                                                                                                                                      1. 1

                                                                                                                                                                                                        I am inclined to agree on this point, though I lack full context and cannot be 100% sure.

                                                                                                                                                                                                  4. 48

                                                                                                                                                                                                    And he actually offers a path forward – keep doing what you’re doing, but know that we’re going to break you, and it’s up to YOU to fix that, not US.

                                                                                                                                                                                                    ?? The Rust guy kept saying over and over that no one is going to force any C dev to fix Rust interfaces. They already offered that path forward! The audience member was strawmanning hard.

                                                                                                                                                                                                    The Rust for Linux is making what seems like a reasonable request for more information on the semantics, so that they can encode it statically in the type system.

                                                                                                                                                                                                    I am not sure, but I suspect the answer is “you have to figure that out yourself because there’s 30 years of history there” … or “that is a misguided way of looking at the problem – the solution does not match reality” [1]

                                                                                                                                                                                                    What you’re saying here is equivalent to saying that it’s impossible for new C code to use the interface correctly because no one actually knows how it’s supposed to work. Asahi Lina actually pointed out something similar about the DRM subsystem here:

                                                                                                                                                                                                    The lifetime requirements were undocumented and boiled down to “design your driver like amdgpu to make it work, or else”.

                                                                                                                                                                                                    My driver is not like amdgpu, it fundamentally can’t work the same way. When I tried to upstream minor fixes to the C code to make the behavior more robust and the lifetime requirements sensible, the maintainer blocked it and said I should just do “what other drivers do”.

                                                                                                                                                                                                    Even when I pointed out that other C drivers also triggered the same bugs because the API is just bad and unintuitive and there are many secret hidden lifetime requirements, he wouldn’t budge.

                                                                                                                                                                                                    1. 32

                                                                                                                                                                                                      Asahi Lina actually pointed out something similar about the DRM subsystem here:

                                                                                                                                                                                                      Fediverse version of that link which (unlike xitter) can be viewed in full without logging in: https://vt.social/@lina/113045455229442533

                                                                                                                                                                                                    2. 37

                                                                                                                                                                                                      I suspect the answer is “you have to figure that out yourself because there’s 30 years of history there” … or “that is a misguided way of looking at the problem – the solution does not match reality”

                                                                                                                                                                                                      But that lays bare a horrible implication: no-one knows how to safely write file-systems against this API then. Regardless of whether it is when writing a Rust wrapper for the API or someone writing a new or maintaining an existing file-system in C.

                                                                                                                                                                                                      1. 26

                                                                                                                                                                                                        Yeah, I was somewhat surprised to find that no one even knows how the ext4 filesystem works. The most authoritative document was basically some guy reverse engineering it with lots of “from what I can tell…” and “I think it does this…”, and after digging through the code I have to say he did a much better job understanding it than I’m capable of doing. It’s still wild to me that something as foundational as a filesystem isn’t specified such that people can write tools to operate on them without having to FFI to the Linux source code.

                                                                                                                                                                                                        1. 20

                                                                                                                                                                                                          Yes, this is how most C and C++ APIs work. People who are horrified, I envy you because it seems like this isn’t something you have to deal with on a daily basis.

                                                                                                                                                                                                          1. 23

                                                                                                                                                                                                            It’s also why Rust (and, to a lesser degree, modern C++) is such a breath of fresh air to so many of us who are used to dealing with giant old C and C++ code bases. Just the fact that Rust encodes lifetime information in the type system eliminates so many questions. When I write against someone else’s C APIs, my biggest question is usually “what are the lifetime requirements of this object? Should I free it? If so, when?”. That question is very rarely answered by documentation, so it’s left up to intuition, reading the implementation, and address sanitizer telling me when I’m leaning something or double-freeing something or use-after-freeing something.

                                                                                                                                                                                                            There are many things about the Rust language that I’m not a huge fan of, and I personally prefer writing C++, but I don’t feel like I can ignore it.

                                                                                                                                                                                                            1. 8

                                                                                                                                                                                                              When I write against someone else’s C APIs, my biggest question is usually “what are the lifetime requirements of this object? Should I free it? If so, when?”. That question is very rarely answered by documentation, so it’s left up to intuition, reading the implementation, and address sanitizer telling me when I’m leaning something or double-freeing something or use-after-freeing something.

                                                                                                                                                                                                              Worse: many codebases don’t have a rule for that, either. I’m guilty of that, too, I think I’ve written at least one long piece of spaghetti code where, halfway through the implementation, I realised that accommodating a particular quirk of some underlying protocol or filesystem required something to be freed based on slightly different conventions than the rest of the code followed.

                                                                                                                                                                                                              Sure, you document that visibly, comment your code, whatever, but wetware sidechannels just aren’t very good for that.

                                                                                                                                                                                                              1. 1

                                                                                                                                                                                                                Should I free it?

                                                                                                                                                                                                                If you get a pointer from a function call, then you should free it, no?

                                                                                                                                                                                                                If so, when?

                                                                                                                                                                                                                Wouldn’t that be after you’re done using it?

                                                                                                                                                                                                                1. 7

                                                                                                                                                                                                                  If you get a pointer from a function call, then you should free it, no?

                                                                                                                                                                                                                  No, and there are even examples in the standard library. For example, you are not supposed to free the char * returned by getenv.

                                                                                                                                                                                                                  1. 7

                                                                                                                                                                                                                    I wish those rules were universal, but they’re not.

                                                                                                                                                                                                              2. 8

                                                                                                                                                                                                                a horrible implication: no-one knows how to safely write file-systems against this API then.

                                                                                                                                                                                                                Is that surprising?

                                                                                                                                                                                                                I wonder in how many C projects the size and age of Linux people really know how the APIs work.

                                                                                                                                                                                                              3. 8

                                                                                                                                                                                                                [1]

                                                                                                                                                                                                                you have a dangling reference here

                                                                                                                                                                                                                1. 2

                                                                                                                                                                                                                  Good job checking that for them

                                                                                                                                                                                                                2. 8

                                                                                                                                                                                                                  [1] Regarding “whether encoding file system semantics statically in the Rust type system is a good idea”

                                                                                                                                                                                                                  Take this with a grain of salt, since I haven’t looked at the specific problem, nor do I have any real expertise in it

                                                                                                                                                                                                                  But I think there is the general problem where some people think “Of course that’s a good idea, why wouldn’t you do that?”

                                                                                                                                                                                                                  And then there is the reality that there are inherently dynamic aspects to software interfaces.


                                                                                                                                                                                                                  I ran into this difference in thinking while working on a garbage collector. Some people want there to always be a static way of doing things, but in this case it’s mathematically impossible (due to Rice’s theorem, etc.).

                                                                                                                                                                                                                  https://lobste.rs/s/8dqbty/my_experience_crafting_interpreter_with#c_a6kmdz

                                                                                                                                                                                                                  GC and rooting are inherently dynamic.

                                                                                                                                                                                                                  I suspect there is a big bridge to gap between Linux kernel dev and Rust for a similar reason

                                                                                                                                                                                                                  It’s a dynamic vs. static way of thinking, and again the answer is going to be somewhere in between.

                                                                                                                                                                                                                  The fallacy of the dynamic side is perhaps a status quo fallacy.

                                                                                                                                                                                                                  The fallacy of the static side is that everything important can be encoded statically. The failure mode is when you only encode the trivial properties, and the cost isn’t worth the benefit. The dynamic techniques for correctness still end up bearing most of the weight, and then you have a static “bureaucracy” off to the side.


                                                                                                                                                                                                                  I suspect @matklad might have some thoughts/opinions on this, e.g. since after using Rust, he’s using Zig and writing more about dynamic properties of software:

                                                                                                                                                                                                                  https://tigerbeetle.com/blog/2023-12-27-it-takes-two-to-contract

                                                                                                                                                                                                                  https://lobste.rs/s/blszfs/it_takes_two_contract

                                                                                                                                                                                                                  https://matklad.github.io/2024/07/05/properly-testing-concurrent-data-structures.html

                                                                                                                                                                                                                  My guess is that the Linux kernel is more like Tiger Beetle … are you going to try to encode the invariants of a transactional database in a type system?

                                                                                                                                                                                                                  Or are you doing to do it with dynamic assertions and the like? (Of course it’s not either-or, but I think there is a contrast philosophically, which is similar to the one between Rust and Zig)


                                                                                                                                                                                                                  I also noticed from the recent thread that the prototype of Tiger Beetle was done in node.js (https://lobste.rs/s/tr8ozm/why_is_spawning_new_process_node_so_slow)

                                                                                                                                                                                                                  To me that suggests that one of the most important properties of the system – performance, and the algorithms you use to get there – don’t benefit that much from static encodings

                                                                                                                                                                                                                  Of course the answer is different for each system, and that’s what makes it hard.

                                                                                                                                                                                                                  (“advice = limited life experience + generalization”)

                                                                                                                                                                                                                  1. 32

                                                                                                                                                                                                                    And then there is the reality that there are inherently dynamic aspects to software interfaces.

                                                                                                                                                                                                                    This is somewhat of a non sequitur. Type systems encode dynamic aspects of programs all the time, especially so in Rust which has sum types. The example API in the talk was doing exactly this.

                                                                                                                                                                                                                    1. 20

                                                                                                                                                                                                                      The simplest example is, I feel, Arc, which statically describes a set of rules for entirely dynamically managing the life cycle of an object. You don’t know which thread is going to end up freeing it, but it’s still safe because the rules lay out why that doesn’t matter.

                                                                                                                                                                                                                      1. 6

                                                                                                                                                                                                                        By “inherently dynamic” I mean “expressing it statically is like solving the halting problem” – i.e. mathematically impossible

                                                                                                                                                                                                                        I didn’t say dynamic – I said inherently dynamic, and gave an example of what I mean


                                                                                                                                                                                                                        For people who don’t understand what I mean, I suggest writing a garbage collector in Rust. It will give you a good perspective on the nature of – and the limitations of – the abstraction you’re using.

                                                                                                                                                                                                                        I also believe there is a pretty strong analogy with the conventions used in say kernels or transactional databases


                                                                                                                                                                                                                        I also recommend reading this article

                                                                                                                                                                                                                        https://kevinlynagh.com/rust-zig/

                                                                                                                                                                                                                        https://lobste.rs/s/eppfav/why_i_rewrote_my_rust_keyboard_firmware

                                                                                                                                                                                                                        for an example of why hardware may not match what your type system can express, which is very relevant to kernel development.

                                                                                                                                                                                                                        Basically, you can be spending a lot of effort solving the wrong problems.

                                                                                                                                                                                                                        The Linux kernel has tons of problems I’m sure, so I’m glad this experiment is being done – but it does still appear to be an experiment.

                                                                                                                                                                                                                        1. 21

                                                                                                                                                                                                                          Your example doesn’t demonstrate what you claim it does. Every property captured by a static type system is already dancing with the halting problem. There is no “inherently dynamic” boundary to cross here.

                                                                                                                                                                                                                          The business of a (sound) type system is to find an approximation of the dynamic property we are interested in, such that it can rule out all the violations without ruling out too many interesting dynamically-valid programs. All Rice’s theorem means is that this will always strictly be an approximation, not that it can’t be good enough for general purpose use.

                                                                                                                                                                                                                          GC rooting is absolutely no exception to this, and the borrow checker is actually uniquely suited to capture this kind of thing- an un-rooted reference is very much like a borrow, during which the collector must wait for a safepoint when the reference is again rooted or discarded. There are several designs for encoding this property in the Rust type system: https://manishearth.github.io/blog/2021/04/05/a-tour-of-safe-tracing-gc-designs-in-rust/

                                                                                                                                                                                                                          Again, while these encodings are approximations, all this really means is that you can’t go crazy passing around un-rooted references in ways that are too complicated for the type system to understand. But this is essentially never something you want to do anyway! These encodings are plenty flexible enough to capture all the typical ways that the mutator holds onto un-rooted references, which are very localized.

                                                                                                                                                                                                                          1. 3

                                                                                                                                                                                                                            You can encode SOME rooting policy, but what about the most efficient (minimal) rooting policy?


                                                                                                                                                                                                                            Do you agree that this is a possible failure mode?

                                                                                                                                                                                                                            The failure mode is when you only encode the trivial properties, and the cost isn’t worth the benefit. The dynamic techniques for correctness still end up bearing most of the weight, and then you have a static “bureaucracy” off to the side.

                                                                                                                                                                                                                            Or is it inconceivable? Is it always better to use the static approach, and there is no tradeoff to make?

                                                                                                                                                                                                                            1. 19

                                                                                                                                                                                                                              I haven’t said anything about which side of the tradeoff is better. I only specifically disagreed with your claim about the “reality” that some things were “inherently” dynamic.

                                                                                                                                                                                                                              But with that out of the way, I think it should also be obvious that nobody is claiming that the static approach is always better. Rust itself uses the dynamic approach for things like bounds checks and integer overflow checks!

                                                                                                                                                                                                                              But even then, your argument is somewhat of a non sequitur: the thing Linux is doing is neither dynamic nor static. It is just an un-checked free-for-all where the human programmer has to manually learn and follow the rules of the API, and when they fail it just corrupts the abstraction.

                                                                                                                                                                                                                              1. 5

                                                                                                                                                                                                                                Right, so if I have a Rust program with an integer i, then it is an inherently dynamic property of that program whether the integer overflows.

                                                                                                                                                                                                                                It’s not a property you can statically encode in the type system. It’s mathematically impossible to do so (in general)

                                                                                                                                                                                                                                Do you agree?


                                                                                                                                                                                                                                Likewise, I claim that software interfaces and especially hardware interfaces have inherently dynamic properties. (I’m not sure if the keyboard firmware example is one, but it appears to be a case where the type system is creating bureaucracy that doesn’t help correctness. It is sort of beating around the bush, and not really helping with the core problem.)

                                                                                                                                                                                                                                You can approximate them with a static property, but it may not be the algorithm or policy you actually want.

                                                                                                                                                                                                                                For example, it might run too slowly, which is why I brought up the GC rooting example.


                                                                                                                                                                                                                                Just because there is no encoding of the file system API in a static type system doesn’t mean that not well-specified, prima facie

                                                                                                                                                                                                                                It could be well specified, but impossible to express in Rust’s type system. Or you can express some part of it in Rust type’s system, but not in a way that actually helps you ship 50 working file systems.

                                                                                                                                                                                                                                It can certainly be be a big mess too – Linux code is messy with many hands in it.


                                                                                                                                                                                                                                Let me additionally quote Tso

                                                                                                                                                                                                                                I suspect the best thing to do is you to continue maintaining your rust bindings

                                                                                                                                                                                                                                over time there will be continued C code refactoring right

                                                                                                                                                                                                                                maybe we will start using you know k3 RCU

                                                                                                                                                                                                                                if that breaks rust, we will find out whether or not this concept of encoding huge amounts of semantics into the type system is a good thing or a bad thing

                                                                                                                                                                                                                                and instead of trying to convince us what is actually correct let’s see what happens in a year or two and it will either work or it won’t and we will see

                                                                                                                                                                                                                                Do you believe that this question makes any sense?

                                                                                                                                                                                                                                Is the idea of encoding semantics in the static type system prima facie a good idea?

                                                                                                                                                                                                                                My feeling from this thread is that many Rust users believe that what he’s saying can’t possibly be an argument, which is what I alluded to in the comment that you replied to.

                                                                                                                                                                                                                                I believe there is a fundamental difference in thinking – and it is more or less accurate to call it dynamic vs. static.

                                                                                                                                                                                                                                On the one side, you have the dynamic “reality”, backed by shipping 50 file systems over a few decades (which implies debugging them), and on the other side you have “we think in static type signatures; the program can’t be correct and can’t be reasoned about unless it passes the type checker”.


                                                                                                                                                                                                                                Tso is not saying it won’t work – he is treating it as an empirical question. But I believe many Rust users do not believe it’s an empirical question.

                                                                                                                                                                                                                                Is it an empirical question?

                                                                                                                                                                                                                                Is it possible for a static type system to model a problem poorly, and get in the way of a correct program? Or are the static types reality itself?

                                                                                                                                                                                                                                1. 14

                                                                                                                                                                                                                                  It’s not a property you can statically encode in the type system. It’s mathematically impossible to do so (in general)

                                                                                                                                                                                                                                  Do you agree?

                                                                                                                                                                                                                                  Absolutely not, for the reasons I already gave. You can use ranged integer types, and reject operations where the ranges of the inputs mean there may be overflow. This is a classic example of encoding a property in the type system.

                                                                                                                                                                                                                                  For example, it might run too slowly, which is why I brought up the GC rooting example.

                                                                                                                                                                                                                                  The GC rooting example does not suggest anything like this. As I already said, the rooting behavior of existing GC languages is already easily local enough that it would not have to change at all to be encoded in a type system.

                                                                                                                                                                                                                                  Do you believe that this question makes any sense?

                                                                                                                                                                                                                                  I repeat: nobody is claiming that the static approach is always better. The reason Rust uses dynamic checking for overflow is not that it would be impossible to encode in the type system, but that they judged it to be more practical to check that particular property at runtime.

                                                                                                                                                                                                                                  You are trying to counter an argument that you completely made up, not anything the Rust language or the Rust-for-Linux project is actually saying. And worse, you are trying to pull me into that argument, which I am entirely uninterested in.

                                                                                                                                                                                                                                  1. 1

                                                                                                                                                                                                                                    This issue came up again and I responded here - https://lobste.rs/s/yx57uf/is_linux_collapsing_under_its_own_weight#c_gvj8fk

                                                                                                                                                                                                                                    (won’t reply again on this thread due to length)

                                                                                                                                                                                                                                  2. 12

                                                                                                                                                                                                                                    (For context: I use and like Rust, but I have ~no opinion on whether it’s a good fit for Linux.)

                                                                                                                                                                                                                                    Is it possible for a static type system to model a problem poorly, and get in the way of a correct program? Or are the static types reality itself?

                                                                                                                                                                                                                                    This feels to me like a false dilemma posed in such as way as to make people either agree with you or appear to agree with an absurd proposition (that static types are “reality itself” and no use of them ever models a problem poorly). Maybe something more concrete can be more constructive….

                                                                                                                                                                                                                                    https://lobste.rs/s/eppfav/why_i_rewrote_my_rust_keyboard_firmware

                                                                                                                                                                                                                                    for an example of why hardware may not match what your type system can express

                                                                                                                                                                                                                                    Likewise, I claim that software interfaces and especially hardware interfaces have inherently dynamic properties. (I’m not sure if the keyboard firmware example is one, …

                                                                                                                                                                                                                                    I get an impression that you use (or previously used) that keyboard firmware post to suggest that Rust is bad for interfacing with hardware, but I still don’t think that keyboard firmware post is relevant.

                                                                                                                                                                                                                                    I think a better example of some Rust code being bad at interfacing with hardware is David Chisnall’s MMIO anecdote (see, e.g., here or here). The details weren’t clearly stated, but it sounded like what was happening in that case was that some Rust code was reading the value of a “device register” as a richly typed value, which is not okay. The solution would be to read the register value as just an integer and then map that to a more richly typed value with plain, safe Rust code like

                                                                                                                                                                                                                                    match raw_value {
                                                                                                                                                                                                                                        0 => Op::Cancel,
                                                                                                                                                                                                                                        1 => Op::Unicast,
                                                                                                                                                                                                                                        2 => Op::Multicast,
                                                                                                                                                                                                                                        3 => Op::Upcast,
                                                                                                                                                                                                                                        4 => Op::Downcast,
                                                                                                                                                                                                                                        ...
                                                                                                                                                                                                                                        _ => return Err(...),
                                                                                                                                                                                                                                    }
                                                                                                                                                                                                                                    

                                                                                                                                                                                                                                    Rust code can use structs and enums and lifetime-equipped references within itself, but, at an interface with hardware like that, Rust code must treat values it gets from the hardware as just bytes, or just integers, not structs or enums or lifetime-equipped references. The device registers’ world is a wild, untyped one whose values mustn’t be eaten raw in Rust’s typed world.

                                                                                                                                                                                                                                    I think the many remarks you’ve made here about “dynamic vs. static” could be more understandable if more concrete examples were given. Does this MMIO example sound relevant to what you’re trying to say about “inherently dynamic properties”?

                                                                                                                                                                                                                                    1. 1

                                                                                                                                                                                                                                      Yeah I could have omitted the last line, but it made me chuckle … I don’t believe the general point is a strawman, because I see a very strong consensus in this thread and elsewhere that if an interface is not expressible in Rust’s static type system, it can’t be a good interface, and should be changed so that it is.

                                                                                                                                                                                                                                      I disagree with that.

                                                                                                                                                                                                                                      Also, I ended up skimming a mailing list thread, and it is very clear to me that it is a clash between the dynamic mindset of kernel devs and static mindset of Rust devs:

                                                                                                                                                                                                                                      https://lwn.net/ml/linux-fsdevel/ZZWhQGkl0xPiBD5%2F@casper.infradead.org/


                                                                                                                                                                                                                                      For the record, I would like the future of kernels to use more static analysis, and static types. I think it would make kernel programming a lot more accessible to me personally, and to everyone, and thus widen the pool of contributors, and make kernels better.

                                                                                                                                                                                                                                      I just think the types need to be appropriate to the problem. And what I am hearing from Tso is that this might be possible, but it’s a question that should be answered empirically.

                                                                                                                                                                                                                                      My suspicion is basically the same as what chisnall and matklad said elsewhere in the thread:

                                                                                                                                                                                                                                      https://lobste.rs/s/46pt2l/retiring_from_rust_for_linux_project#c_eqlhxb

                                                                                                                                                                                                                                      There is a “Rust view of the world”, and Rust has a very specific aliasing model. I would even say that Rust is domain-specific language – because all languages are.

                                                                                                                                                                                                                                      And type safety is a global property of a program.

                                                                                                                                                                                                                                      This makes it harder to migrate an existing codebase like Linux, with its own specific model. The models clash.

                                                                                                                                                                                                                                      I believe what they are saying is not substantially different from Tso’s suspicion – it’s just expressed with less shouting

                                                                                                                                                                                                                                      But like I said, it’s an empirical question that will (eventually) be answered …


                                                                                                                                                                                                                                      The MMIO issue with unsafe does seem relevant and important, though not exactly what I was thinking of

                                                                                                                                                                                                                                      There were 2 related claims

                                                                                                                                                                                                                                      • some interfaces are inherently dynamic
                                                                                                                                                                                                                                      • some things can be expressed statically, but they might not help you with the core of the problem

                                                                                                                                                                                                                                      As for examples:

                                                                                                                                                                                                                                      It “feels” like RCU is “inherently dynamic”, with respect to the Rust type system, though I have no expertise in this area:

                                                                                                                                                                                                                                      https://en.wikipedia.org/wiki/Read-copy-update#Sample_RCU_interface

                                                                                                                                                                                                                                      https://lwn.net/Articles/653326/#Other%20RCU%20Flavors

                                                                                                                                                                                                                                      Can the Rust type system say anything about this? Can it statically eliminate errors in obeying these protocols?

                                                                                                                                                                                                                                      I could certainly be underestimating what it can express

                                                                                                                                                                                                                                      My suspicion is if that it were shown that Rust could statically check all usages of RCU protocols, kernels developers would be JUMPING to learn and use Rust

                                                                                                                                                                                                                                      But I think Rust doesn’t help there. The Rust way would be to introduce some other mechanism that’s probably not as finely tuned.


                                                                                                                                                                                                                                      I read over this story and thread again - https://lobste.rs/s/eppfav/why_i_rewrote_my_rust_keyboard_firmware

                                                                                                                                                                                                                                      As an aside, the top comment seems to be from a pretty experienced Rust programmer, who expresses an opinion that Rust penalizes RUNTIME behavior in favor of its “model” (async/await in this case):

                                                                                                                                                                                                                                      The fixation on async-await, despite it slowing down almost every real-world workload it is applied to, and despite it adding additional bug classes and compiler errors that simply don’t exist unless you start using it, has been particularly detrimental to the ecosystem.

                                                                                                                                                                                                                                      That is basically what I mean by models vs dynamic reality.

                                                                                                                                                                                                                                      • You want make a fast concurrent system - the reality is what it does, what syscalls it makes, how many requests per second it can handle, etc.
                                                                                                                                                                                                                                      • The model is using say async/await vs. C vs. Zig. Each of the languages has different tools / a different model for reasoning about the dynamic behavior of programs.

                                                                                                                                                                                                                                      The keyboard post also expresses something like this:

                                                                                                                                                                                                                                      I just wanted to blink the little squares on the screen on and off very quickly.

                                                                                                                                                                                                                                      That is what has to happen in reality. And the author is very neutral and agnostic about which tool will be used to get there – it is very problem-focused rather than tool-focused.

                                                                                                                                                                                                                                      Does it have some examples of where Rust’s type systems misrepresents reality?

                                                                                                                                                                                                                                      Reading over it, I think it’s closer to “the type system made my life hard”, and when I used Zig, with a weaker type system, was a breath of fresh air.

                                                                                                                                                                                                                                      Though there is some good humility at the end – it is possible that tradeoff can change over time, as the program evolves and is maintained by more people

                                                                                                                                                                                                                                      Nonetheless I think this is similar to the issues that I suspect will result in continued clashes on the Rust for Linux project.

                                                                                                                                                                                                                                      1. 9

                                                                                                                                                                                                                                        I don’t believe the general point is a strawman, because I see a very strong consensus in this thread and elsewhere that if an interface is not expressible in Rust’s static type system, it can’t be a good interface, and should be changed so that it is.

                                                                                                                                                                                                                                        I haven’t seen that at all here, actually.

                                                                                                                                                                                                                                        1. 0

                                                                                                                                                                                                                                          Hm I just noticed this sentence in the Wikipedia page:

                                                                                                                                                                                                                                          The RCU infrastructure observes the time sequence of rcu_read_lock, rcu_read_unlock, synchronize_rcu, and call_rcu invocations in order to determine when (1) synchronize_rcu invocations may return to their callers and (2) call_rcu callbacks may be invoked.

                                                                                                                                                                                                                                          “Observing the time sequence” certainly sounds “inherently dynamic” to me!

                                                                                                                                                                                                                                          1. 8

                                                                                                                                                                                                                                            You are describing an implicit state machine, and the question is whether you can encode the valid state transitions in the type a way that is useful in Rust’s type system. In many cases like this you can.

                                                                                                                                                                                                                                            This may still result in dynamic checks - but in those cases, the type will guide you to insert those checks, and the code will not compile without them.

                                                                                                                                                                                                                                            There is a field called choreographic programming which goes much deeper into encoding this kind of stuff in types than what you can do in Rust, too, if you are interested in that kind of thing.

                                                                                                                                                                                                                                            1. 1

                                                                                                                                                                                                                                              This issue came up again and I responded here - https://lobste.rs/s/yx57uf/is_linux_collapsing_under_its_own_weight#c_gvj8fk

                                                                                                                                                                                                                                              (won’t reply again on this thread due to length)

                                                                                                                                                                                                                        2. 3

                                                                                                                                                                                                                          You’re not alone as I understood it the same way as you. It almost felt to as the kind of discussion I’d hear in the corporate world.

                                                                                                                                                                                                                          New member of the dev team: “We could rewrite this like that and it would be so much better!”

                                                                                                                                                                                                                          Veteran of the dev team: “Yeah it could be better long term but you do understand that we have to keep releasing the product at a steady rate and while the old stuff is not perfect, it does work and it is what everyone here knows.”

                                                                                                                                                                                                                          1. 18

                                                                                                                                                                                                                            You may not know this, but Rust for Linux is an experiment to see whether Rust would be a good fit for the kernel, and Linus Torvalds is quite supportive of it. Some senior maintainers who dislike Rust are not content to let the experiment simply run its course, they are obstructing it.

                                                                                                                                                                                                                            New member of the dev team: “We could rewrite this like that and it would be so much better!”

                                                                                                                                                                                                                            Veteran of the dev team: “Yeah it could be better long term but you do understand that we have to keep releasing the product at a steady rate and while the old stuff is not perfect, it does work and it is what everyone here knows.”

                                                                                                                                                                                                                            But the actual situation is that Rust is proposed to be used in new drivers, not rewriting tons of stuff. And the veterans are not being respectful and thoughtful about how they respond, they are being caustic shitheads.

                                                                                                                                                                                                                            1. 3

                                                                                                                                                                                                                              Some senior maintainers who dislike Rust are not content to let the experiment simply run its course, they are obstructing it.

                                                                                                                                                                                                                              Wouldn’t that be part of the experiment though? In grade school we might say: “my hypothesis is that not everyone will love rust and welcome it with open arms”.

                                                                                                                                                                                                                              1. 33

                                                                                                                                                                                                                                How are they supposed to test if it will work well if some maintainers simply block all work? Linus said that writing an fs module in Rust would be a great test for Rust in Linux. When Rust people ask for stuff from the fs people, stuff that they’d need even if they were writing C, like “what is the correct way to use this interface?”, the maintainers get caustic and go on rants about how the Rust people are pushing a religion.

                                                                                                                                                                                                                                It’s completely fucking unhinged.

                                                                                                                                                                                                                          2. 8

                                                                                                                                                                                                                            It’s the same rhetoric, the same vibe. Instead of screaming ‘they are shoving GENDER IDEOLOGY down our throat’ they are screaming ‘they are shoving the religion of SUBSTRUCTURAL TYPE SYSTEMS down our throat’.

                                                                                                                                                                                                                      2. 5

                                                                                                                                                                                                                        The compiler for Futhark is an interesting case of a compiler where all of the internal representations have a textual representation that you can print, edit and load back in to debug specific internal compiler passes.

                                                                                                                                                                                                                        There’s not a lot of publicly available documentation about this aspect of Futhark (perhaps it would make for an interesting experience report or a workshop paper), but how it works is basically that you can take a Futhark program like this

                                                                                                                                                                                                                        def main [n] (xs: [n]i64) : [n]i64 =
                                                                                                                                                                                                                          map (+ 1) xs
                                                                                                                                                                                                                        

                                                                                                                                                                                                                        and get the GPUMem internal representation (which includes an abstract representation of GPU kernels and memory allocations, use -v to see all the other passes the compiler goes through on the way):

                                                                                                                                                                                                                        types {
                                                                                                                                                                                                                        
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        
                                                                                                                                                                                                                        entry("main",
                                                                                                                                                                                                                              {xs: []i64},
                                                                                                                                                                                                                              {[]i64})
                                                                                                                                                                                                                          entry_main (xs_mem_5232 : mem@device,
                                                                                                                                                                                                                                      n_5194 : i64,
                                                                                                                                                                                                                                      xs_5195 : [n_5194]i64 @ xs_mem_5232 ->
                                                                                                                                                                                                                                                {offset: 0i64;
                                                                                                                                                                                                                                                 strides: [1i64];
                                                                                                                                                                                                                                                 shape: [n_5194]})
                                                                                                                                                                                                                          : {mem@device,
                                                                                                                                                                                                                             [n_5194]i64 @ ?0@device ->
                                                                                                                                                                                                                             {offset: 0i64;
                                                                                                                                                                                                                              strides: [1i64];
                                                                                                                                                                                                                              shape: [n_5194]}#([2], [1])} = {
                                                                                                                                                                                                                          let {bytes_5234 : i64} =
                                                                                                                                                                                                                            mul_nw64(8i64, n_5194)
                                                                                                                                                                                                                          let {segmap_tblock_size_5225 : i64} =
                                                                                                                                                                                                                            get_size(segmap_tblock_size_5217, thread_block_size)
                                                                                                                                                                                                                          let {segmap_usable_groups_5226 : i64} =
                                                                                                                                                                                                                            sdiv_up64(n_5194, segmap_tblock_size_5225)
                                                                                                                                                                                                                          let {mem_5235 : mem@device} =
                                                                                                                                                                                                                            alloc(bytes_5234, @device)
                                                                                                                                                                                                                          let {defunc_0_map_res_5227 : [n_5194]i64 @ mem_5235 ->
                                                                                                                                                                                                                                                       {offset: 0i64;
                                                                                                                                                                                                                                                        strides: [1i64];
                                                                                                                                                                                                                                                        shape: [n_5194]}} =
                                                                                                                                                                                                                            segmap(thread; ; grid=segmap_usable_groups_5226; blocksize=segmap_tblock_size_5225)
                                                                                                                                                                                                                            (gtid_5228 < n_5194) (~phys_tid_5229) : {i64} {
                                                                                                                                                                                                                              let {eta_p_5230 : i64} =
                                                                                                                                                                                                                                xs_5195[gtid_5228]
                                                                                                                                                                                                                              let {lifted_lambda_res_5231 : i64} =
                                                                                                                                                                                                                                add64(1i64, eta_p_5230)
                                                                                                                                                                                                                              return {returns lifted_lambda_res_5231}
                                                                                                                                                                                                                            }
                                                                                                                                                                                                                          in {mem_5235, defunc_0_map_res_5227}
                                                                                                                                                                                                                        }
                                                                                                                                                                                                                        

                                                                                                                                                                                                                        You can modify this, for instance by changing the 1i64 on the fifth last line to 2i64 and compile the modified IR with (note the file extension):

                                                                                                                                                                                                                        futhark dev --backend=opencl tmp.fut_gpu_mem
                                                                                                                                                                                                                        

                                                                                                                                                                                                                        Finally, this modified program can be run with echo [1i64, 2i64] | ./tmp to see the changed output.

                                                                                                                                                                                                                        The IR representations are not particularly pretty, but when you squint a little, they look a bit like the source language, and it is possible (if not pleasant) to hand write.

                                                                                                                                                                                                                        1. 2

                                                                                                                                                                                                                          That is really cool! Would love to be able to read about some of the design considerations for this IR.

                                                                                                                                                                                                                        2. 4

                                                                                                                                                                                                                          For me the hardest part of using NixOS on servers is getting NixOS there in the first place. After you achieve that, then managing servers and stuff is a bliss, but that first step - ugh, can be rough.

                                                                                                                                                                                                                          1. 1

                                                                                                                                                                                                                            I’ve been using cloud-init and nixos-infect for that. Have you taken a look? At its simplest, this is what I use on Hetzner:

                                                                                                                                                                                                                            runcmd:
                                                                                                                                                                                                                              - curl https://raw.githubusercontent.com/elitak/nixos-infect/master/nixos-infect | PROVIDER=hetznercloud NIX_CHANNEL=nixos-23.05 bash 2>&1 | tee /tmp/infect.log
                                                                                                                                                                                                                            

                                                                                                                                                                                                                            I did also experiment a bit with terraform, inspired by this blogpost by @cadey. I worked it into a nice setup, but ultimately went a different route, for unrelated reasons.

                                                                                                                                                                                                                            1. 3

                                                                                                                                                                                                                              Yes, but nixos-infect sometimes failed for me on OVH VPS and Google Cloud. Why? I have no idea. I would love to have NixOS more broadly available as one of the base images available, that would make everything so much easier.

                                                                                                                                                                                                                              1. 1

                                                                                                                                                                                                                                Tried as well, sometimes doesn’t work and then good luck finding out why and how to fix it.

                                                                                                                                                                                                                                1. 1

                                                                                                                                                                                                                                  Usually the step that was being performed points directly at the area that was wrong. Also - one you have a working one for a given hosting provider & type of machine (bare metal vs VPS) etc. it works 100% of time every time like magic.