1. 3

    I found that having loads of E2E tests often doesn’t add all that much; usually they’re all doing the exact same thing test after test after test, and since these parts tend to be fairly isolated there isn’t all that much that can go wrong in only that specific test. Either it works for everything, or it fails for everything.

    The way I’ve always viewed E2E tests is as “testing everything at the top layers” such as middleware, HTTP handling, and whatnot, which you can usually do with just a few (or sometimes even one) test. Other less high-level integration tests can test all the rest, and they tend to run much faster as they avoid a lot of overhead, and are a lot easier to write and reason about, especially if tests fail since you actually have some access to the system. Plus, it’s much easier to get code coverage (which I find useful to inspect which code is being run, not because I care about metric).

    I once rewrote a E2E test suite to use integration tests which gave a massive speed-up, and because the tests were a lot easier work with people actually started writing them. I added a few E2E tests (IIRC logging in, viewing the dashboard, logging out) and that was enough really.

    1. 1

      Agreed - you want a very few E2E tests that verify the basic core functionality works at all. “You can view pages and log in.” Even logging out seems like too much. Authoring content? Meh, an outage will be bad but bearable.

      1. 2

        Logging out seems useful because it’s a very “special” action, same as logging in. In general if I’d add E2E tests at all then I’d test every type of request, including authoring content by the way, or something like uploading files if that’s something your app has, as all of them do actually test something useful and have different code paths.

        If you’re going to do E2E testing at all then it doesn’t really matter if you have 2, 6, or 10 of them; all are manageable numbers (As opposed to hundreds or thousands of them).

        1. 2

          Uploading files is a good one.

          The point of E2E tests is to make sure you didn’t do something to the framework that breaks all functionality. As an example bug, a Rails middle ware that conditionally hijacks requests has its condition inverted. Or the JS minifier decided to output a file containing “error. Blah blah” instead of actual JavaScript.

          File upload paths are finicky enough that they’d be easy to break in a way only an E2E test could reasonably catch.

          The number of assertions in the test doesn’t really matter, what matters is runtime. And every request, every back and forth with the server, adds runtime to this commit-approval-blocking test.

    1. 26

      The article treats Go and Rust as on equal footing when it comes to safety. This is quite wrong, unless “safety” refers only to memory safety: Rust is far safer than Go in general, for a number of reasons: algebraic data types with exhaustive pattern matching, the borrow checker for statically preventing data races, the ability to use RAII-like patterns to free resources automatically when they go out of scope, better type safety due to generics, etc.

      Of course, both languages are safer than using a dynamically typed language. So from the perspective of a Python programmer, it makes sense to think of Go as a safer alternative.

      There may be certain dimensions along which it makes sense to prefer Go over Rust, such as the learning curve, the convenience of a garbage collector, etc. But it’s important to be honest about each language’s strengths and weaknesses.

      1. 22

        On the other hand, if you do think about memory safety, it’s not quite so clear cut. In Go, I can create a cyclic data structure without using the Unsafe package and the GC will correctly collect it for me. In Rust, I have to write custom unsafe code to both create it and clean it up. In Go I can create a DAG and the GC will correctly clean it up. In Rust, I must use unsafe (or a standard-library crate such as RC that uses unsafe internally) to create it, and clean it up.

        However, in Go I can create an object with a slice field and share it between two goroutines and then have one write update it in a loop with a small slice and a large slice and the other goroutine read until it sees the base of the small slice and the length of the large slice. I now have a slice whose bounds are larger than the underlying object and I can violate all of the memory-safety invariants without writing a single line of code using the Unsafe package. In Rust, I could not do this without incorrectly implementing the Sync trait, and you cannot implement the Sync trait without unsafe code.

        Go loses its memory safety guarantees if you write concurrent software. Rust loses its memory safety guarantees if you use non-trivial data structures. C++ loses its memory safety guarantees if you use pointers (or references).

        1. 12

          Go loses its memory safety guarantees if you write concurrent software. Rust loses its memory safety guarantees if you use non-trivial data structures. C++ loses its memory safety guarantees if you use pointers (or references).

          This is fantastically succinct. Thanks, I might use this myself ;)

          1. 6

            In Rust, I have to write custom unsafe code to both create it and clean it up

            No, you really don’t.

            You can create it with no unsafe code (outside of the standard library) and no extra tracking by using Box::leak, it will just never be cleaned up.

            You can create it with no unsafe code (outside of the standard library) and reference counted pointers by using Rc::new for forward pointers and Rc::downgrade for back pointers, and it will be automatically cleaned up (at the expense of adding reference counting).

            You can make use of various GC and GC like schemes with no unsafe code (outside of well known libraries), the most famous of which is probably crossbeam::epoch.

            You can make use of various arena datastructures to do so with no unsafe code (outside of well known libraries), provided that that form of “GC all at once at the end” fits your use case, e.g. typed arena.

            1. 3

              You can create it with no unsafe code (outside of the standard library)

              The parenthetical here is the key part. The standard library implementations for all of the things that you describe all use unsafe.

              1. 6

                No, it isn’t. That’s how the entire language works, encapsulate and abstract unsafe things until they are safe. To argue otherwise is to argue that every allocation is bad, because implementing an allocator requires unsafe (and the standard library uses unsafe to do so)…

                Unsafe code is not viral.

                1. 1

                  Note also that the Rust Standard library has special dispensation for unsafe and unstable features – it can assume a particular compiler version, it can use unsafe code that would be unsound without special knowledge of the compiler, and it can compel the compiler to change in order to support what the stdlib wants to do.

            2. 13

              Of course, both languages are safer than using a dynamically typed language.

              I wish people would stop saying that. Especially with “of course”. We can believe all we want, but there is no data supporting the idea that dynamically typed languages are inherently less safe. Again, I don’t care why you think it should be the case. First show me that it actually is, then try to hypothesize as to why.

              1. 21

                I often find production bugs in dynamically typed systems I work on which are due to issues that would be caught be a type checker for a modern type system (e.g., null reference errors, not handling a case of an algebraic data type when a new one is added, not handling new types of errors as the failure modes evolve over time, etc.). That’s an existence proof that having a type checker would have helped with safety. And this is in a codebase with hundreds of thousands of tests and a strict code review policy with code coverage requirements, so it wouldn’t be reasonable to attribute this to an insufficient test suite.

                Very large companies are migrating their JavaScript codebases to TypeScript precisely because they want the safety of static types. Having been privy to some of those discussions, I can assure you there were made with a lot of consideration due to the enormous cost of doing so.

                Going down the academic route, dependent types let you prove things that tests cannot guarantee, such as the fact that list concatenation is associative for all inputs. I personally have used Coq to prove the absence of bugs in various algorithms. As Dijkstra said, “program testing can be used to show the presence of bugs, but never to show their absence”. Types, on the other hand, actually can show the absence of bugs if you go deep enough down the rabbit hole (and know how to formally express your correctness criteria).

                You don’t have to believe me, and perhaps you shouldn’t since I haven’t given you any specific numbers. There are plenty of studies, if you care to look (for example, “A Large Scale Study of Programming Languages and Code Quality in Github; Ray, B; Posnett, D; Filkov, V; Devanbu, P”). But at the same time, there are studies that claim the opposite, so for this topic I trust my personal experience more than the kind of data you’re looking for.

                1. 2

                  Yet Go lacks many of those features, such as algebraic data types, exhaustive switches, and has both nil and default values.

                  1. 3

                    Yes, hence my original claim that Rust is far safer than Go. But Go still does have a rudimentary type system, which at least enforces a basic sense of well-formedness on programs (function arguments being the right type, references to variables/functions/fields are not typos, etc.) that might otherwise go undetected without static type checking. Since these particular types of bugs are also fairly easy to catch with tests, and since Go programs often rely on unsafe dynamic type casting (e.g., due to lack of generics), Go is not much safer than a dynamically typed language—in stark contrast to Rust. I think one could reasonably argue that Go’s type system provides negligible benefit over dynamic typing (though I might not go quite that far), but I do not consider it reasonable to claim that static types in general are not capable of adding value, based on my experience with dependent types and more sophisticated type systems in general.

                    1. 2

                      Since these particular types of bugs are also fairly easy to catch with tests, and since Go programs often rely on unsafe dynamic type casting (e.g., due to lack of generics), Go is not much safer than a dynamically typed language—in stark contrast to Rust.

                      But only <1% of Go code is dynamically typed, so why would you argue that it’s not much safer than a language in which 100% of code is dynamically typed? Would you equally argue that because some small amount of Rust code uses unsafe that Rust is no safer than C? These seem like pretty silly arguments to make.

                      In my experience writing Go and Rust (and a whole lot of Python and other languages), Go hits a sweet spot–you have significant type safety beyond which returns diminish quickly (with respect to safety, anyway). I like Rust, but I think your claims are wildly overstated.

                  2. 2

                    so for this topic I trust my personal experience more than the kind of data you’re looking for.

                    I wonder how much of this is us as individual programmers falling into Simpson’s Paradox. My intuition says that for large, complex systems that change infrequently, static typing is a huge boon. But that’s only some portion of the total programs being written. Scientific programmers write code that’s more about transmitting mathematical/scientific knowledge and easily changeable for experimentation. Game scripters are looking for simple on-ramps for them to change game logic. I suspect the “intuitive answer” here highly depends on the class of applications that a programmer finds themselves working on. I do think there’s an aspect of personality here, where some folks who enjoy abstraction-heavy thinking will gravitate more toward static typing and folks who enjoy more “nuts-and-bolts” thinking may gravitate toward dynamic typing. Though newer languages like Nim and Julia are really blurring the line between dynamic and static.

                    1. 2

                      Have you done Coq to prove the correctness of anything that wasn’t easy by inspection? I’ve looked at it and I’m definitely interested in the ideas (I’m working through a textbook in my spare time), but I’ve never used it to prove anything more complicated than, say, linked list concatenation or reversing.

                      And how do you generate the program from your code? Do you use the built-in extraction, or something else?

                      1. 2

                        I often find production bugs in dynamically typed systems I work on that are due to things that would be caught be a type checker

                        I can offer an equally useless anecdotal evidence of my own practice where bugs that would be caught by a type checked happen at a rate of about 1/50 to those caused by mis-shapen data, misunderstanding of domain complexity and plain poor testing, and when they do, they’re usually trivial to detect and fix. The only thing that tells me is that software development is complex and we are far from making sweeping statements that start from “of course”.

                        Very large companies are migrating their JavaScript code bases to TypeScript for exactly for that reason.

                        Sorry, the “thousand lemmings” defense won’t work here. Out whole industry has been investing countless engineer-years in OO abstractions, but then people started doing things without it and it turned out OO wasn’t the requirement for building working systems. Software development is prone to fads and over-estimations.

                        Types, on the other hand, actually can show the absence of bugs

                        That’s just plain wrong. Unless you mean some very specific field of software where you can write a formal specification for a program, but to this day it’s just not practical for anything that’s useful.

                        1. 5

                          It’s clear that many people find value in static types even if you don’t. Maybe you make fewer mistakes than the rest of us, or maybe you’re working in a domain where types don’t add as much value compared to others. But you shouldn’t try to invalidate other people’s experiences of benefitting from static types.

                          they’re usually trivial to detect and fix

                          I prefer to eliminate entire categories of errors without having to detect and fix them down the line when they’ve already impacted a user.

                          That’s just plain wrong.

                          Maybe you haven’t used formal verification before, but that doesn’t mean it isn’t used in the real world. There’s a great book series on this topic if you are interested in having a more open mind. I’ve used these kind of techniques to implement parts of a compiler that are guaranteed correct. Amazon also uses deductive techniques in multiple AWS teams (example), and there’s a decent chance you have indirectly benefitted from some of those efforts. So, my claim is not “just plain wrong”. As you alluded to, it usually doesn’t make sense to invest that much in those kinds of formal guarantees, but it’s nice that types can do that for you when you need them to.

                          At this point, it seems like you aren’t interested in having a good faith discussion, with your abrasive comments like “I don’t care why you think it should be the case”, “equally useless anecdotal evidence”, and dismissing a demonstrable claim as “just plain wrong”. I think you have some good points (e.g., I completely agree about your position on OO) and could be more effective at delivering them if you didn’t seem so invested in discounting other people’s experiences.

                          I respect your opinion that I should not have stated that Rust and Go are “of course” safer than dynamically typed languages. In particular, Go’s type system is so underpowered that I can see a reasonable argument that the ceremony of appeasing it without reaping the guarantees that a better type system would give makes it more difficult to build robust software than not having types at all. I certainly wouldn’t say the same for Rust, though. Rust often forces me to handle error cases that I didn’t even know were possible and would never think to test.

                          1. 1

                            But you shouldn’t try to invalidate other people’s experiences of benefitting from static types.

                            Go’s type system is so underpowered that I can see a reasonable argument that the ceremony of appeasing it without reaping the guarantees that a better type system would give makes it more difficult to build robust software than not having types at all.

                            Do you not think this is invalidating the experience of Go users who benefit from usage of the language?

                            1. 1

                              I said I could see it as a reasonable argument, not that I personally agree with it. I’m trying to give some validity to what isagalaev is saying and potentially meet them in the middle by acknowledging that not all type systems provide a clear benefit over dynamic typing. But I already stated my stance in my original top-level comment: that Go’s type system is still better than no type system when it comes to safety (not memory safety, but a more broad notion of safety).

                              It is true, though, that Go’s type system is quite weak compared to other type systems. That’s not the same as saying that people don’t benefit from it. On the contrary, I’ve claimed the opposite—which is what started this whole discussion in the first place.

                            2. 1

                              abrasive comments

                              Apologies on that, fwiw.

                            3. 2

                              […] caused by mis-shapen data, […]

                              Statements like these always make me suspect the author doesn’t appreciate just how much can in fact be captured by even a relatively simple type system. “Make illegal states unrepresentable” has become something of a mantra in the Elm community in particular, and I can’t remember the last time I saw a bug in a typed FP language that was due to “mis-shappen data” get past the type checker.

                              I think there’s a tendency to try to compare languages by lifting code wholesale from one language into the other, assuming it would be written more or less the same way, which is often not the case. So, if you see a something that throws TypeError, of course you assume that would get caught by a static type system. Folks who have only worked with type systems like those in Java/Go/C generally look at null/nil bugs and assume that those wouldn’t get caught, even though they’re impossible in other systems. It’s easy to point out “null isn’t a thing in this language,” but what’s a bit harder to capture is that a lot of things that aren’t obviously type errors that crop up at runtime in a dynamically typed language would likely be captured by types in a program writing with the benefit of a modern type system. Obviously it won’t if you just write a stringly-typed program, but… don’t do that, use your tools.

                              1. 1

                                “Make illegal states unrepresentable” has become something of a mantra in the Elm community in particular, and I can’t remember the last time I saw a bug in a typed FP language that was due to “mis-shappen data” get past the type checker.

                                It’s not about illegal states. I mean code expecting a response from an HTTP call in a particular schema and getting a different one. I don’t see how this problem can be prevented at compile time. Or more subtly, getting data in a correct shape (say, an ISO-formatted time string), successfully parsing it (into an internal datetime type), but then producing the result that the user doesn’t expect because it assumes the time to be in a different time zone.

                                (Also, I don’t see how making illegal states unrepresentable is in any way endemic to type-checked languages. It’s just a good architectural pattern valid everywhere.)

                                1. 1

                                  I mean code expecting a response from an HTTP call in a particular schema and getting a different one.

                                  Ah, you are talking about something somewhat different then. Yes, obviously types can’t statically prove that inputs that come in at runtime will be well-formed. However, they can force you to deal with the case of a parse failure – which many languages make it really easy to forget. “Forgetting a case” is another one of those things that I think people often incorrectly assume aren’t (or can’t easily be made) type errors. It’s hard to say what you should do in that case without more context, but it makes it hard to introduce a bug by omission.

                                  If the bug is just that the programmer was mistaken about what the endpoint’s schema was (or the server operator changed it inappropriately), I’ll agree that just having static types in your client program does not really help that much, though it might be a bit easier to track down since the error will occur right at the point of parsing, rather than some time later when somebody tries to use the value.

                                  That said, I’ll point to stuff like protobuf, capnproto, and even swagger as things that are trying to bridge this gap to some degree – there is still an opportunity to just assign the entirely wrong schema to an endpoint, but they narrow the space over which that can happen substantially; once you’ve got the right schema rigged up the programmer is unlikely to get the shape of the data wrong, as that’s just defined in the schema.

                                  Or more subtly, getting data in a correct shape (say, an ISO-formatted time string), successfully parsing it (into an internal datetime type), but then producing the result that the user doesn’t expect because it assumes the time to be in a different time zone.

                                  Dealing with fiddly distinctions like this is something types are really great at. I have some good points of comparison with date/time stuff, as I’ve worked on projects where this stuff is core to the business logic in both Python and Haskell. Having a type system for it in Haskell has been a godsend, and I wish I’d had one available when doing the prior project.

                                  Somewhat simplified for presentation (but with the essentials in-tact), the Haskell codebase has some types:

                                  • A date & time with an attached (possibly arbitrary) time zone, “ZonedDateTime”
                                  • A date & time in “local time,” where the timezone is implied by context somehow. “LocalDateTime”

                                  As an example of where this is useful: the code that renders the user’s feed of events in order expects a list of LocalDateTime values, so if you try to pass it the datetime with some arbitrary timezone, you’ll get a type error. Instead, there’s a function timeInZone which takes a ZonedDateTime and a TimeZone, and translates it to a LocalDateTime with the provided timezone implied. So in order to get an event into a users feed, you need to run it through this conversion function, or it won’t type check.

                                  (Also, I don’t see how making illegal states unrepresentable is in any way endemic to type-checked languages. It’s just a good architectural pattern valid everywhere.)

                                  It’s a lot easier to do it when you can actually dictate what the possible values of something are; if in the event of a bug a variable could have any arbitrary value, then your options for enforcing invariants on the data are much more limited. You can put asserts everywhere, but having static types is much much nicer.

                          2. 6

                            Also, people talk about “dynamic languages” like they’re all the same, while they are often as different as C and Rust, if not more.

                            Writing safe Javascript is an impossible nightmare..

                            Writing safe Python is easy and fun. I do think it would be safer with a good type-system, but at the same time, a shorter and more idiomatic code (where you don’t have to fight with the compiler) brings its own sort of safety and comfort.

                            1. 4

                              Writing safe Python is easy and fun.

                              Python has its own share of footguns, such as passing strings somewhere where bytes are expected, or new, unhandled exceptions being added to libraries you’re calling.

                              Mypy doesn’t completely protect you. IME, many errors occur at the seams of typed/untyped contexts. Which is not surprising, but it is a downside of an after-the-fact, optional type checker.

                              1. 1

                                Yeah, and mypy has far less coverage for third-party packages than TypeScript. IME when I use TS I’m surprised if I don’t find a type package, whereas with mypy I’m surprised if I do.

                                1. 1

                                  About one in twenty times I do see a types package in DefinitelyTyped which is very incorrect. Almost always only with libraries with small user bases.

                                  1. 1

                                    Incorrect as in “this parameter is a number but is typed as a string”, or too loose/too restrictive?

                                    1. 1

                                      Varies. I’ve seen symbols typed as strings, core functionality missing, functions that couldn’t be called without “as any”.

                                2. 1

                                  Python isn’t perfect, but unhandled exceptions can happen in C++ too..

                                  It doesn’t have to be after the fact. You can check types at run-time, and there are libraries that will help you with that. It comes at a slight performance cost, of course (but if that matters, why are you using Python?), but then you gain the ability to implement much more sophisticated checks, like contracts, or dependent types.

                                  Anyway, at least personally, type errors are rarely the real challenge when writing software.

                              2. 3

                                there is no data supporting the idea that dynamically typed languages are inherently less safe

                                If we use the Gary’s Types document for the definition of a dynamically typed language, I am able to find some research:

                                I do agree that this amount of research is far away from us being able to say “of course”.

                                1. 3

                                  Not gonna take a position here on the actual static vs dynamic debate, but the second paper you linked is deeply flawed. I wrote a bit about the paper, and the drama around it, here: https://www.hillelwayne.com/post/this-is-how-science-happens/

                                  1. 1

                                    Awesome! Thank you for sharing.

                                2. 2

                                  I think it stands to reason that statically typed languages are safer than dynamically typed languages. I’m vaguely aware of some studies from <2005 that compared C++ to Python or some such and found no significant difference in bugs, but I can’t imagine those findings would hold for modern mainstream statically typed languages (perhaps not even C++>=11). Personally I have extensive experience with a wide array of languages and my experience suggests that static typing is unambiguously better than dynamic typing; I hear the same thing from so many other people and indeed even the Python maintainers–including GVR himself–are compelled. Experience aside, it also stands to reason that languages in which entire classes of errors are impossible would have fewer errors in total.

                                  So while perhaps there isn’t conclusive data one way or the other, experience and reason seem to suggest that one is better than the other.

                                  1. 1

                                    Experience aside, it also stands to reason that languages in which entire classes of errors are impossible would have fewer errors in total.

                                    What this (very common) argument is missing is that a) those errors are not as frequent as the words “entire classes of errors” may lead to believe, that b) testing covers many of those errors better (by testing for correct values you’re getting correct types for free), and that c) instrumenting your code with types isn’t free, you get bloated and more rigid code that may lead to more serious errors in modeling your problem domain.

                                    1. 4

                                      I’ve personally found that relying on a decent type system makes my code more flexible, as in easier to refactor, because I can rely on the type system to enforce that all changes are valid.

                                      1. 1

                                        I’ve developed and operated Python services in production for about a decade. Type errors were the most common kind of errors we would encounter by a wide margin. We were very diligent about writing tests, but inevitably we would miss cases. Some of these were “this function is literally just an entry point that unmarshals JSON and passes it into a library function… I don’t need a test” but they would forget to await the library function.

                                        Moreover, how do you reconcile “annotating your code takes too much time and makes your code too inflexible, but writing tests is good value for money”? Am I misunderstanding your argument? Note also that tests are useful for lots of other things, like documentation, optimizations, refactoring, IDE autocomplete, etc.

                                        1. 1

                                          Moreover, how do you reconcile “annotating your code takes too much time and makes your code too inflexible, but writing tests is good value for money”?

                                          Types are not a replacement for tests, you have to write tests anyway. And they are good value for money, which is one of the few things we actually know about software development. So the proposition I’m making is that if you write good tests they should cover everything a type checker would. Because, essentially, if you check all your values are correct then it necessarily implies that types of those values are correct too (or at least, they work in the same way).

                                          Now, to your point about “but inevitably we would miss cases” — I’m very much aware of this problem. I blame the fact that people write tests in horribly complicated ways, get burnt out, never achieve full test coverage and then turn to type checking to have at least some basic guarantees for the code that’s not covered. I’m not happy with this, I wish people would write better tests.

                                          You example with a test for a trivial end point is very telling in this regard. If it’s trivial, then writing a test for it should also be trivial too, so why not?

                                          1. 1

                                            I disagree. In my extensive experience with Python and Go (15 and 10 years, respectively), Go’s type system grants me a lot more confidence even with a fraction of the tests of a Python code base. In other words, a type system absolutely is a replacement for a whole lot of tests.

                                            I specifically disagree that checking for a value guarantees that the logic is correct (type systems aren’t about making sure the type of the value is correct, but that the logic for getting the value is sound).

                                            While 100% test coverage would make me pretty confident in a code base, why burn out your engineers in pursuit of it when a test system would reduce the testing load significantly?

                                            With respect to “trivial code thus trivial tests”, I think this is untrue. Writing “await foo(bar, baz)” is trivial. Figuring out how to test that is still cognitively burdensome, and cognition aside it’s many times the boilerplate.

                                            Lastly, people rarely discuss how static type systems make it harder to write certain kinds of bad code than dynamic type systems. For example, a function whose return type varies depending on the value of some parameter. The typical response from dynamic typing enthusiasts is that this is just bad code and bad Go code exists too, which is true but these kinds of bad code basically can’t exist in idiomatic Go code and they are absolutely pedestrian in Python and JavaScript.

                                            At a certain point, you just have to get a lot of experience working with both systems in order to realize that the difference is really quite stark (even just the amount of documentation you get out of the box from type annotations, and the assurance that that documentation is correct and up to date).

                                            1. 1

                                              I specifically disagree that checking for a value guarantees that the logic is correct

                                              I didn’t say anything about the whole logic. I said if your values are correct then it necessarily implies your types are correct. Specifically, if you have a test that does:

                                              config = parse_config(filename)
                                              assert config['key'] == 'value'
                                              

                                              Then it means that parse_config got a correct value in filename that it could use to open and parse the config file. In which case it also means filename was of correct type: a string, or a Path or whatever the language’s stdlib could use in open(). That’s it, nothing philosophical here.

                                              While 100% test coverage would make me pretty confident in a code base, why burn out your engineers in pursuit of it

                                              Let me reiterate: if achieving 100% test coverage feels like a burn-out, you’re doing it wrong. It’s actually not even hard, especially in a dynamic language where you don’t have to dependency-inject everything. I’m not just fantasizing here, that’s what I did in my last three or four code bases whenever I was able to sell people on the idea. There’s this whole ethos of it being somehow impossibly hard which in many applications just doesn’t hold up.

                                              1. 1

                                                Some more :-)

                                                Writing “await foo(bar, baz)” is trivial. Figuring out how to test that is still cognitively burdensome, and cognition aside it’s many times the boilerplate.

                                                Huh? The tooling is out there, you don’t have to invent anything: https://pypi.org/project/pytest-asyncio/

                                                @pytest.mark.asyncio
                                                async def test_some_asyncio_code():
                                                    res = await library.do_something()
                                                    assert b'expected result' == res
                                                

                                                At a certain point, you just have to get a lot of experience working with both systems in order to realize that the difference is really quite stark

                                                Just to clarify here, I mostly work in Python, but I also work extensively in JavaScript, TypeScript, Kotlin and Rust (much less in the latter than I would like). And my experience tells me that types is not the most significant feature that makes a language safe (for whatever value of “safe”). It is also subjective. I do absolutely trust you that you find working in Go more comfortable, but it’s important to understand that the feeling doesn’t have to be universal. I would hate to have to program in Go, even though it’s a simple language.

                                      2. 1

                                        Genuine question: how could it be shown? You would need at least two projects of similar scope, in similar areas, written by programmers of similar skill (which is hard to evaluate on its own) and similar level of understanding of the problem area (which means that rewrites of the same code base can’t count), differing only in their choice of static/dynamic typing. How could such a research be possible?

                                        More generally: is there any solid research about which languages are better? Is there any data that programs written is the assembly language are more or less error-prone than those written in Python? This should be intuitively obvious, but is there data? I tried to find anything at all, but only discovered half-baked “studies” that don’t control for either the programmer experience or the complexity of the problem area.

                                        My point is, how can we do better than a bunch of anecdotes here?

                                        1. 3

                                          Right, I think one can admit that, as a field, we’re not in amazing shape epistemologically, but we are still left having to actually make decisions in our day to day, so not having opinions isn’t really an option – we’re stuck going on experience and anecdote, but that’s not quite the same as having no information. It’d be nice to have conclusive studies. Unfortunately, all I’ve got is a career’s worth of anecdata.

                                          I have no idea how to study this kind of thing.

                                          1. 3

                                            Yep, this was exactly my point: when someone asks for studies that conclusively show that X is better than Y in this context, I think that they are asking for too much and people are justified in saying “of course” even in the abscence of rock-solid evidence.

                                          2. 2

                                            I would go so far as to argue that, often, when people insist on data for something like this, they are actually being disingenuous. If you insist on (quantitative) data when you know that none exist or are likely to exist in the future, then you are actually just saying that you want to unquestioningly maintain the status quo.

                                            1. 2

                                              I would go so far as to argue that, often, when people insist on data for something like this, they are actually being disingenuous.

                                              … Why would it be disingenuous to ask for data? This just sounds absurd. Moreover there really isn’t consensus around this topic. Take a look at Static v. dynamic languages literature review, this has been an ongoing topic of discussion and there still isn’t a conclusion either way. Regardless this perspective frightens me. It sounds a lot like “I have an opinion and data is hard so I’m going to call you disingenuous for disagreeing with me.” This isn’t the way to make good decisions or to tolerate nuanced opinions.

                                              “The problem with any ideology is it gives the answer before you look at the the evidence. So you have to mold the evidence to get the answer you’ve already decided you’ve got to have.” – Bill Clinton

                                              1. 2

                                                Why would it be disingenuous to ask for data?

                                                It isn’t, and I didn’t say that it was.

                                                I said it was potentially disingenuous to insist on (quantitative) data as a prerequisite for having a discussion. If good data don’t exist, then refusing to talk about something until good data do exist is just another way of defending whatever the status quo is. What it basically says is that regardless of how we made the current decision (presumably without data, since data don’t exist), the decision cannot be changed without data.

                                                I’m honestly not sure how you came up with that interpretation based on what I wrote. I didn’t even say which side of the issue I was on.

                                                Edit: you can also substitute “inconclusive data” for “no data”.

                                                1. 2

                                                  I’m honestly not sure how you came up with that interpretation based on what I wrote. I didn’t even say which side of the issue I was on.

                                                  I think this is a difference between our interpretations on “insist”. I tend to read “insist” as an earnest suggestion, not a hard prerequisite, so that’s where my my disagreement came from. I didn’t mean to imply anything about which side you were on since that’s immaterial to my point really. I agree that categorically refusing to discuss without sufficient data is a bit irresponsible since in real life humans are often forced to make decisions without appropriate evidence.

                                                  If good data don’t exist, then refusing to talk about something until good data do exist is just another way of defending whatever the status quo is.

                                                  My thinking here is, at what point does this become a useless thought exercise? Static typing isn’t new and is gaining ground in several languages. There’s already a “programmer personality” identity based around static typing and “healthy” Twitter communities of folks who bemoan static or dynamic languages. At some point, the programming community at large gains nothing by having more talking heads philosophizing about where and why they see bugs. You can take a cursory search on the internet and see folks advocating for pretty much any point on the spectrum of this debate. To me this discussion (not this Lobsters thread, but the greater discussion as a whole) seems to have reached the point where it’s useless to proceed without data because there’s no consensus around which point on the spectrum of static/dynamic does actually lead to fewer (if any point does at all) bugs. And if more philosophizing doesn’t help us arrive at a conclusion, it really boils down to the same thing: your personal feelings and experiences, in which case the discussion is more of a form of socializing than a form of actual discussion. In other words, without data, this discussion trends more toward bikeshedding than actually answering the question under discussion.

                                                  1. 2

                                                    In other words, without data, this discussion trends more toward bikeshedding than actually answering the question under discussion.

                                                    That’s fair. I agree that this particular topic has been pretty well discussed to death.

                                                    1. 1

                                                      there’s no consensus around which point on the spectrum of static/dynamic does actually lead to fewer (if any point does at all) bugs

                                                      I think consensus is emerging slowly—static languages seem to have grown more popular in the last decade to the extent that many JavaScript developers are converting to TypeScript, Python developers are embracing Mypy, most (all?) of the most popular new languages of the last 10-15 years have been statically typed (the Go community in particular seems to consist of a lot of former Python and Ruby devs), etc. On the other hand, I scarcely if ever hear about people switching to dynamically typed languages (once upon a time this was common, when the popular static offerings were C, C++, and Java). It’s possible that this emerging consensus is just a fad, but things do seem to be converging.

                                                  2. 1

                                                    I suspect the problem is that this question is enormously multivariate (skill of developers, development methodology, testing effort to find bugs, different language features, readability of the language, etc).

                                                    It’s entirely likely that we have been studying this for a long time and yet the variable space is so large that we’ve hardly scratched it at all. And then some people come along and interpret this lack of conclusive data as “well, static and dynamic must be roughly equal” which seems strictly more périlleuse than formulating one’s own opinion based on extensive experience with both type systems.

                                                    I don’t think your Clinton quote applies because we’re talking about forming an opinion based on “a career’s worth of anecdata”, not letting an ideology influence one’s opinion. Everyone admits that anecdata is not as nice as conclusive empirical data, but we don’t have any of the latter and we have lots of the former and it seems to point in a single direction. In this case the ideological take would be someone who forms an opinion based on lack of evidence and lack of subjective experience with both systems.

                                                2. 1

                                                  Genuine question: how could it be shown? You would need at least two projects of similar scope, in similar areas, written by programmers of similar skill (which is hard to evaluate on its own) and similar level of understanding of the problem area (which means that rewrites of the same code base can’t count), differing only in their choice of static/dynamic typing. How could such a research be possible?

                                                  Remember that “project scope”, “project area” (systems, web, database, etc), “license status” (GPLv3, proprietary, etc) are all dimensions for a project that can be recorded and analyzed. There is a rich literature of statistical methods to compensate for certain dimensions being over or underrepresented, and for compensating for incomplete data. If we can come up with a metric for being error-prone (which is difficult, so perhaps we need multiple metrics (NB: Code complexity metrics are a good look here to look at the challenges)), and we can faithfully record other dimensions of projects, we can try to rigorously answer this question. The big barriers here usually involve data siloing (proprietary projects rarely share relevant data about their projects) and just manpower (how many developers, especially of open source projects, really have the time to also gather stats about their contributors and their bugs when they can barely hold together the project itself in their generous free time, or can get approval in a proprietary project).

                                                  That said there’s this stubborn “philosopher-programmer” culture in programming circles that doesn’t seem particularly interested in epistemological work which also often muddles the conversation, especially if the topic under discussion has a lot of strong opinions and zealotry involved.

                                                  1. 1

                                                    The short answer is, I don’t know. I had some ideas though. Like an experiment where you solicit a public participation from a bunch of people to write from scratch something not complicated, and yet not trivial. Like, I don’t know, a simple working chat client for an existing reference server implementation. You don’t impose any restriction: people could work in any language, use libraries, etc. Time capped by, say, a couple of weeks. And then you independently verify the results and determine defects of any sort. And then you look at correlations: does number of defects correlate with dynamic/static nature? Programmer’s experience? Programmer’s experience with a language? Amount of active working hours? Something else?

                                                    My hypothesis is that we can’t actually evaluate a language in a vacuum. Instead a language+programmer is a actually an atomic unit of evaluation. Like in auto racing you can’t say which driver is the best (although it’s people’s favorite pastime), you can only talk about a driver in a particular car driving on particular tracks.

                                                    1. 2

                                                      There is a 1994 paper called “Haskell vs. Ada vs. C++ an Experiment in Software Prototyping Productivity” which doesn’t touch on static vs dynamic typing, but, I think, follows about the same format as what you’re proposing, right? That paper is widely disliked due to its methodological problems. An example of its discussion: https://news.ycombinator.com/item?id=14267882

                                                  2. 1

                                                    We can believe all we want, but there is no data supporting the idea that dynamically typed languages are inherently less safe

                                                    I think that some people tend to use the term “safe” to mean both “memory-safe” and “bug-resistant”, whereas others would use the term “safe” to refer to “memory-safe” only.

                                                    I can quite believe that applications written in dynamically-typed languages might be vulnerable to a whole class of bugs that aren’t present in their statically-typed equivalents because, unless you’re very careful, type coercion can silently get you in ways you don’t expect. You could write an entire book on the many mysterious ways of the JavaScript type system, for example.

                                                    That said, these aren’t really bugs that make the program unsafe if you’re talking about memory safety. It’s not terribly likely that these sorts of bugs are going to allow unsafe memory accesses or cause buffer overflows or anything of the sort.

                                                    1. 2

                                                      applications written in dynamically-typed languages might be vulnerable to a whole class of bugs [ … ] , type coercion can silently get you in ways you don’t expect.

                                                      Dynamic languages is not just JavaScript. For example Python and Clojure don’t do type coercion, nor do they silently swallow access to non-existing names and attributes.

                                                  3. 4

                                                    Of course, both languages are safer than using a dynamically typed language. So from the perspective of a Python programmer, it makes sense to think of Go as a safer alternative.

                                                    Returns also diminish. Using Go rather than Python will probably reduce type errors by 95% while Rust would reduce them by 99%. And that additional 4% of type errors may not be worth the hit to productivity (yes, I assert that Go is quite a lot more productive than Rust for most applications, even though I am a fan of both languages). Note also that these are just type errors; there are lots of errors which neither Rust nor Go can protect against.

                                                    1. 5

                                                      there are lots of errors which neither Rust nor Go can protect against.

                                                      “How does your language handle null references?”

                                                      Prohibited by the type system at compile time.

                                                      “Nice, nice. What about out-of-bounds array accesses?”

                                                      Sometimes detectable even at compile time and at any rate detected and safely handled at runtime.

                                                      “Wonderful. So obviously then if your allocator reports that you’ve run out of memory…”

                                                      Instant, unrecoverable crash, yes.

                                                      1. 2

                                                        I’m not sure how that relates to my “there are lots of errors which neither Rust nor Go can protect against.” statement that you’re quoting. Yes, those are categories of errors that Rust protects against and Go does not, but there are still lots of other errors that neither language protect against.

                                                        1. 1

                                                          My point is that one of the errors that neither protect you against is out-of-memory errors, which has always baffled me. Rust doesn’t even panic (which could be recovered), but aborts.

                                                          OOM is much more often treated as a situation where it’s seemingly okay to absolutely crash compared to other resource-exhaustion situations (nobody would be like “oh the disk is full, let’s just crash and not even attempt to let the programmer deal with it”).

                                                          1. 2

                                                            I don’t know the rationale for this in Rust, but I’m aware that there’s been some discussion of this in the C++ standards committee. Gracefully handling out-of-memory conditions sounds really useful, but there are two problems:

                                                            • In several decades of the C++ specification defining exception behaviour for operator new exhausting memory and longer for C defining malloc as returning NULL when allocation fails, there are no examples of large-scale systems outside of the embedded / kernel space that gracefully handle memory exhaustion in all places where it can occur. Kernels generally don’t use the standard may-fail APIs and instead use two kinds of allocations, those that may block and those that may fail, with the vast majority of uses being the ones that can block.
                                                            • Most *NIX systems deterministically report errors if you exhaust your address space (which is not easy on a 64-bit system) but don’t fail on out-of-memory conditions at the allocation point. They will happily report that they’ve allocated memory but then fault when you try to write to it.

                                                            If you do get an out-of-memory condition, what do you do? If you’re disciplined and writing a very low-level system, then you do all of your allocation up-front and report failure before you’ve tried any processing. For anything in userspace, you typically need to do a load of cleanup, which may itself trigger allocation.

                                                            In general, the set of things for which it is possible to gracefully handle allocation failure are so distinct from everyday programming that it’s difficult to provide a generic mechanism that works for both. This is what malloc(3) and malloc(9) are such different APIs.

                                                            1. 2

                                                              Part of the trouble is that in most languages, it’s really hard to actually do much of anything without further allocation. Especially in languages where allocation can happen implicitly, this really does seem like an “above the program’s pay grade” kind of thing.

                                                              That said, Rust is decidedly not one of those languages; this is an API design choice, and it has indeed often felt like an odd one to me.

                                                    1. 2

                                                      I haven’t been following Rocket lately? What are the big features/changes that folks are looking forward to?

                                                      1. 4

                                                        Sounds like the big ones are support for async, and running on the stable compiler.

                                                      1. 4

                                                        If you want to use an online password manager, I would recommend using the one already built into your browser. They provide the same functionality, and can sidestep these fundamental problems with extensions.

                                                        Except that they don’t support sharing passwords, let alone role-based access controls.

                                                        1. 3

                                                          You’re doing role based access control using passwords and a password manager?

                                                          So when e.g. somebody loses a role you change the pw and update it in everybody’s manager?

                                                          And when something gets screwed up you only know that it was somebody who had the password because everybody uses the same account?

                                                          Imho password sharing is an anti-feature.

                                                          1. 5

                                                            B2B vendors have a nasty habit of mandating one account per customer company instead of one account per human. Password sharing solves this problem.

                                                            1. 1

                                                              And it gets even more fun when the vendor has “you must change your password every 30 days” rules, which was a constant headache with dozens of one-login-per-company vendors at my last job.

                                                            2. 2

                                                              Many people have multiple computing devices, sharing allows you to use the same password store on all of them instead of having to laboriously setup and manage multiple password stores.

                                                              1. 1

                                                                Oh, yeah, that’s fine and can be handled using a shared db. This was about sharing with other people. :)

                                                              2. 1

                                                                My girlfriend and I share passwords for a couple sites (streaming ones, mostly). It’s not role-based because there’s just two of us, and we could just let each other know if the password has to be changed, but it’s not an anti-feature.

                                                                1. 1

                                                                  I think it is an anti-feature because it prevents the proper security requirements unless you also have some kind of shared master password.

                                                                  The password manager company should simply not be able to share your password with someone because they should not be able to access it.

                                                                2. 1

                                                                  So when e.g. somebody loses a role you change the pw and update it in everybody’s manager?

                                                                  And when something gets screwed up you only know that it was somebody who had the password because everybody uses the same account?

                                                                  It’s mostly me, but I have multiple environments that require varying levels of access. It’s mainly to try and contain the damage from a breach on any one device. It sucks, but very few sites/services allow you to enable access to different users.

                                                              1. 12

                                                                These look really neat. Can’t quite tell a lot from the pictures, but I expect some sort of servicing guide to be excerpted later. Lots of OCP green “touch this”, like you can see on the screws around the CPU.

                                                                (Tagged the story as illumos because it looks like it is, based on https://github.com/oxidecomputer/illumos-gate/tree/cross.vmm-vm.wip )

                                                                1. 6

                                                                  Also this: https://github.com/oxidecomputer/propolis

                                                                  They mentioned that a hypervisor is part of the assumed stack, and it looks like it’s bhyve on illumos.

                                                                  1. 7

                                                                    Does anything in particular make Illumos a better hypervisor than Linux? I have no particular reason to believe either is better, except that Linux gets a lot more developer hours.

                                                                    1. 2

                                                                      I would not be at all surprised if the maturity of the Illumos ZFS implementation was a bigger consideration than bhyve vs. kvm. Storage is just as much a part of this story as CPU or chassis, so having a rock-solid underlying filesystem that can support all those VMs efficiently seems like a good default.

                                                                      1. 3

                                                                        As far as I know, ZFS on Illumos and ZFS on Linux are the same these days (as of 2.0). Of course that wasn’t true when Oxide started, so you could be right.

                                                                        Thinking on it more, Bryan Cantrill does have years of experience running VMs on Illumos (SmartOS) at Joyent, and years more experience with Illumos / Solaris in general. Although I think SmartOS mixed in Linux KVM for virtualization, not bhyve.

                                                                        Ultimately I guess it doesn’t matter. Hosted applications are VMs. As long as it works, no one needs to care whether it’s Illumos, Linux, or stripped down iMacs running Hypervisor.framework.

                                                                        Another point for Illumos: eBPF has come a long way, but DTrace already works. Since they made a DTrace USDT library for Rust I think it’s safe to assume DTrace influenced their choice to use Illumos.

                                                                    2. 2

                                                                      So this has me wondering what happens if they decide they need arm64 hardware? How portable is Illumos?

                                                                      1. 1

                                                                        It supports SPARC CPUs with the SUN heritage, so it should be portable to arm when needed, no?

                                                                      2. 1

                                                                        Missed opportunity for zones, then!

                                                                      3. 3

                                                                        illumos

                                                                        Did you expect Cantrill to support epoll and dnotify?

                                                                        1. 8

                                                                          epoll is actually terrible and a a huge argument against Linux game servers where I used to work.

                                                                          io_uring is pretty sane as an interface though.

                                                                      1. 31

                                                                        Zig’s cross-compilation story is the best I’ve ever seen. It’s so good I didn’t even think it would be possible. Even if Zig-the-language never gains any traction (which would be a tragedy), Zig-the-toolchain is already fantastic and will be around for a long time.

                                                                        Go’s is good, don’t get me wrong, but Zig solves a much harder problem and does it so amazingly seamlessly.

                                                                        1. 16

                                                                          To be honest, the difficulty of cross compilation is something I have never really understood. A compiler takes source code written in some human readable formalism, and produces binary code in some machine readable formalism. That is it. It’s frankly baffling, and a testament to a decades long failure of our whole industry, that “cross compilation” is even a word: it is after all just like compilation: source code in, machine code out. We just happen to produce machine code for other systems than the one that happens to host the compiler.

                                                                          I see only two ways “cross” compilation can ever be a problem: limited access to target specific source code, and limited access to the target platform’s specifications. In both cases, it looks to me like a case of botched dependency management: we implicitly depend on stuff that vary from platform to platform, and our tools are too primitive or too poorly designed to make those dependencies explicit so we can change them (like, depending on the target platform’s headers and ABI instead of the compiler’s platform).

                                                                          I would very much like to know what went wrong there. Why is it so hard to statically link the C standard library? Why do Windows programs need VCRedists? Can’t a program just depend on it’s OS’s kernel? (Note: I know the security and bloat arguments in favour of dynamic linking. I just think solving dependency hell is more important.)

                                                                          1. 9

                                                                            Why is it so hard to statically link the C standard library?

                                                                            Well, because glibc… Maybe musl will save us 😅

                                                                            If you really want to go down that rabbit hole: https://stackoverflow.com/a/57478728

                                                                            1. 8

                                                                              Good grief, glibc is insane. What it does under the hood is supposed to be an implementation detail, and really should not be affected by linking strategy. Now, this business about locales may be rather tricky; maybe the standard painted them into a corner: from the look of it, a C standard library may have to depend on more than the kernel¹ to fully implement itself. And if one of those dependencies does not have a stable interface, we’re kinda screwed.

                                                                              When I write a program, I want a stable foundation to ship on. It’s okay if I have to rewrite the entire software stack to do it, as long as I have stable and reliable ways to make the pixels blinks and the speaker bleep. Just don’t force me to rely on flaky dependencies.

                                                                              [1]: The kernel’s userspace interface (system calls) is very stable. The stackoverflow page you link to suggests otherwise, but I believe they’re talking about the kernel interface, which was never considered stable (resulting in drivers having to be revised every time there’s a change).

                                                                              1. 5

                                                                                It’s worth noting (since your question was about generic cross-platform cross-compilation, and you mentioned e.g. Windows) that this comment:

                                                                                The kernel’s userspace interface (system calls) is very stable.

                                                                                is only really true for Linux among the mainstream operating systems. In Solaris, Windows, macOS, and historically the BSDs (although that may’ve changed), the official, and only stable, interface to the kernel, is through C library calls. System calls are explicitly not guaranteed to be stable, and (at least on Windows and Solaris, with which I’m most familiar) absolutely are not: a Win32k or Solaris call that’s a full-on user-space library function in one release may be a syscall in the next, and two separate syscalls in the release after that. This was a major, major issue with how Go wanted to do compilation early on, because it wanted The Linux Way to be the way everywhere, when in fact, Linux is mostly the odd one out. Nowadays, Go yields to the core C libraries as appropriate.

                                                                                1. 1

                                                                                  As long as I have some stable interface, I’m good. It doesn’t really matter where the boundary is exactly.

                                                                                  Though if I’m being honest, it kinda does: for instance, we want interfaces to be small, so they’re easier to stabilise and easier to learn. So we want to find the natural boundaries between applications and the OS, and put the stable interface there. It doesn’t have to be the kernel to be honest.

                                                                            2. 3

                                                                              I agree it is over complicated, but it isn’t as simple as you are saying.

                                                                              One answer is because many tools want to run code during the build process, so they need both compilers and a way to distinguish between the build machine and target machine. this does not need to be complicated, but immediately breaks your idealized world view.

                                                                              Another answer is our dependency management tools are so poor it is not easy to setup the required libraries to link the program for the target.

                                                                              1. 1

                                                                                many tools want to run code during the build process

                                                                                Like, code we just compiled? I see two approaches to this. We could reject the concept altogether, and cleanly separate the build process itself, that happens exclusively on the source platform from, tests, that happen exclusively on the target platform. Or, we could have a portable bytecode compiler and interpreter, same as Jonathan Blow does with his language. I personally like going the bytecode route, because it make it easier to have a reference implementation you can compare to various backends.

                                                                                a way to distinguish between the build machine and target machine.

                                                                                As far as I understand, we only need a way to identify the target machine. The build machine is only relevant insofar as it must run the compiler and associated tools. Now I understand how that alone might be a problem: Microsoft is not exactly interested in running MSVC on Apple machines… Still, you get the idea.

                                                                                Another answer is our dependency management tools are so poor it is not easy to setup the required libraries to link the program for the target.

                                                                                Definitely.

                                                                                1. 1

                                                                                  Like, code we just compiled?

                                                                                  There are two common cases of this. The first is really a bug in the build system: try to compile something, run it, examine its behaviour, and use that to configure the build. This breaks even the really common cross-compilation use case of trying to build something that will run on a slightly older version of the current system. Generally, these should be rewritten as either try-compile tests or run-time configurable behaviour.

                                                                                  The more difficult case is when you have some build tools that are built as part of the compilation. The one that I’m most familiar with is LLVM’s TableGen tool. To make LLVM support cross compilation, they needed to first build this for the host, then use it to generate the files that are compiled for the target, then build it again for the target (because downstream consumers also use it). LLVM is far from the only project that generates a tool like this, but it’s one of the few that properly manages cross compilation.

                                                                                  1. 1

                                                                                    Oh, so that what you meant by distinguishing the build platform from the target platform. You meant distinguishing what will be build for the host platform (because we need it to further the build process) from the final artefacts. Makes sense.

                                                                                    1. 1

                                                                                      Another example would be something like build.rs in rust projects, though that seems less likely to cause problems. The linux kernel build also compiles some small C utilities that it then uses during the build so they have HOSTCC as well as CC.

                                                                              2. 2

                                                                                The concept of self hosted language is fading away. The last truly self hosted language might have been Pascal.

                                                                                1. 4

                                                                                  On its surface this sounds preposterous. Can you elaborate? I know of maybe a dozen self-hosted languages since Pascal so I think I must be misunderstanding.

                                                                                  Edit: I’m guessing you mean that not only is the compiler self-hosted, but every last dependency of the compiler and runtime (outside the kernel I guess?) is also written in the language? That is a much more limited set of languages (still more than zero) but it’s not the commonly accepted meaning of self-hosted.

                                                                                  1. 3

                                                                                    The original Project Oberon kernel was written in assembly, but the newer version is written almost entirely in Oberon.

                                                                                    Some of the early Smalltalks were written almost entirely in Smalltalk, with a weird syntactic subset that had limited semantics but compatible syntax that could be compiled to machine code.

                                                                                    And of course LISP machines, where “garbage collection” means “memory management.”

                                                                                    1. 3

                                                                                      Yes the latter. Sorry, maybe the terminology I used is off.

                                                                                      1. 2

                                                                                        It’s an interesting distinction even if the terminology isn’t what I’d use. There’s a trend right now among languages to hop on an existing runtime because rebuilding an entire ecosystem from first principles is exhausting, especially if you want to target more than one OS/architecture combo. Sometimes it’s a simple as just “compile to C and benefit from the existing compilers and tools for that language”. But it seems fitting that we should have a way to describe those systems which take the harder route; I just don’t know what the word would be.

                                                                                  2. 1

                                                                                    limited access to the target platform’s specifications. […] it looks to me like a case of botched dependency management

                                                                                    This is exactly what’s going on. You need to install the target platform’s specifications in an imperative format (C headers), and it’s the only format they provide.

                                                                                    And it makes extreme assumptions about file system layout, which are all necessarily incorrect because you’re not running on that platform.

                                                                                  3. 5

                                                                                    Could you elaborate on what “the harder problem” is?

                                                                                    1. 26

                                                                                      Go can cross-compile Go programs but cgo requires an external toolchain even natively; cross compiling cgo is a pain.

                                                                                      Zig compiles Zig and C from almost any platform to almost any platform pretty seamlessly.

                                                                                      1. 4

                                                                                        Zig compiles Zig and C from almost any platform to almost any platform pretty seamlessly.

                                                                                        As I understand it, Zig doesn’t do much more than clang does out of the box. With clang + lld, you can just provide a directory containing the headers and libraries for your target with --sysroot= and specify the target with -target. Clang will then happily cross-compile anything that you throw at it. Zig just ships a few sysroots pre-populated with system headers and libraries. It’s still not clear to me that this is legal for the macOS ones, because the EULA for most of them explicitly prohibits cross compiling, though it may be fine if everything is built from the open source versions.

                                                                                        This is not the difficult bit. It’s easy if your only dependency is the C standard library but most non-trivial programs have other dependencies. There are two difficult bits:

                                                                                        • Installing the dependencies into your sysroot.
                                                                                        • Working around build systems that don’t support cross compilation and so try to compile and run things and dependencies that are compiler-like.

                                                                                        The first is pretty easy to handle if you are targeting an OS that distributes packages as something roughly equivalent to tarballs. On FreeBSD, for example, every package is just a txz with some metadata in it. You can just extract these directly into your sysroot. RPMs are just cpio archives. I’ve no idea what .deb files are, but probably something similar. Unfortunately, you are still responsible for manually resolving dependencies. It would be great if these tools supported installing into a sysroot directly.

                                                                                        The second is really hard. For example, LLVM builds a tablegen tool that generates C++ files from a DSL. LLVM’s build system supports cross compilation and so will first build a native tablegen and then use that during the build. If you’re embedding LLVM’s cmake, you have access to this. If you have just installed LLVM in a sysroot and want to cross-build targeting it then you also need to find the host tablegen from somewhere else. The same is true of things like the Qt preprocessor and a load of other bits of tooling. This is on top of build systems that detect features by trying to compile and run something at build time - this is annoying, but at least doesn’t tend to leak into downstream dependencies. NetBSD had some quite neat infrastructure for dealing with these by running those things in QEMU user mode while still using host-native cross-compile tools for everything else.

                                                                                        1. 1

                                                                                          As I understand it, Zig doesn’t do much more than clang does out of the box. With clang + lld, you can just provide a directory containing the headers and libraries for your target with –sysroot= and specify the target with -target. Clang will then happily cross-compile anything that you throw at it. Zig just ships a few sysroots pre-populated with system headers and libraries.

                                                                                          That’s what it does but to say that it “isn’t much more than what clang does out of the box” is a little disingenuous. It’s like saying a Linux distro just “packaged up software that’s already there.” Of course that’s ultimately what it is, but there’s a reason why people use Debian and Fedora and not just Linux From Scratch everywhere. That “isn’t much more” is the first time I’ve seen it done so well.

                                                                                          1. 1

                                                                                            It solves the trivial bit of the problem: providing a sysroot that contains libc, the CSU bits, and the core headers. It doesn’t solve the difficult bit: extending the sysroot with the other headers and libraries that non-trivial programs depend on. The macOS version is a case in point. It sounds as if it is only distributing the headers from the open source Apple releases, but that means that you hit a wall as soon as you want to link against any of the proprietary libraries / frameworks that macOS ships with. At that point, the cross-compile story suddenly stops working and now you have to redo all of your build infrastructure to always do native compilation for macOS.

                                                                                  1. 6

                                                                                    HardenedBSD has OpenTTD 1.10.3 in its package repo. We even apply an exploit mitigation called SafeStack to it. ;-P

                                                                                    1. 1

                                                                                      Doesn’t the application of different options make multiplayer determinism issues worse, though?

                                                                                      1. 1

                                                                                        I’m unsure I understand your question. Can you rephrase?

                                                                                        1. 1

                                                                                          I reverse my stance, this is a good thing - if a compiler security mitigation like stack hardening causes a desync, that means the mitigation was triggered during play.

                                                                                    1. 6

                                                                                      That is because a long term standard must be extensible. Thus the fields can not be fixed and it must be possible to add new types.

                                                                                      The new wisdom is “have one joint and keep it well oiled”. Last I heard, PGP was still having problems with the message authentication hash upgrade.

                                                                                      All you have to do is directly transcribe these cases into a case statement and you are done. There is no real thinking required.

                                                                                      This is only correct if out of bounds reads are not something you need to worry about, which is not correct in PGP’s favorite implementation language.

                                                                                      Since this is from the public key section of the PGP published standard it might be interesting to compare with the same sort of thing from the Signal Protocol

                                                                                      Wait, we were talking about packet parsing and you criticize Signal for not providing “identity information outside the program”? Massive non sequitur, and I can hardly call GPG’s “human only output” policy as proper access (see e.g. GDPR’s opinion on “machine readable” data exports). Additionally, from what I can tell this was an intentional design decision, so it’s misleading to describe it as “missing” from the standard.

                                                                                      RSA with 2048 bit keys is a perfectly reasonable and conservative default.

                                                                                      Uh, what year is it? 1024 bit RSA is considered too short now. 2048 is a perfectly reasonable minimum, not conservative at all.

                                                                                      Most people prefer to keep their identity indefinitely.

                                                                                      This statement demonstrates a blatant misunderstanding of the complaint.

                                                                                      But apparently the author does not understand why authenticated encryption is not used or even required for the things that PGP is normally used for.

                                                                                      I briefly read the author’s citation; the argument can be paraphrased as “attacks (such as oracle attacks) on the lack of authenticated encryption are impossible, because you can’t automate PGP processing.” This is a bold claim for a piece of software, frankly.

                                                                                      PGP’s signatures are cryptographically strong and are indeed intended to both prove that a particular entity sent a message and that message was delivered as sent. They work very well in practice and are normally used. […] and that is the third time the fact that MDCs can be stripped is mentioned […] Quite excessive when talking about a feature that is not normally used in PGP.

                                                                                      Again, this is a staggering indictment of the author’s lack of understanding of the criticisms. This could only be an acceptable response if we pretend that signature forgery via ciphertext malleability isn’t a thing that exists.

                                                                                      Of course, if you allege that your software is impossible to automate, then you can try to pretend that IND-CCA2 doesn’t matter.

                                                                                      16 whole bits of security.

                                                                                      this statement is quite misleading […] guessing with only a one in 2^16 (65536) chance

                                                                                      More reading comprehension problems. The rebuttal is reiterating the complaint in a different tone of voice. But of course, our software is impossible to automate, so 16 bits of security is plenty.

                                                                                      There is no such “reference PGP implementation”.

                                                                                      This is simply being obtuse. OpenPGP and GPG are practically indistinguishable.

                                                                                      If they were distinguishable, the community would be forced to recognize that the spec is insecure as soon as you automate usage, which brings in decryption oracles and enabling all the attacks that Walzer has dismissed as irrelevant.

                                                                                      it forces the user to comprehend the existence of a key in a way where it is intuitively obvious

                                                                                      Let me just slide this one against this earlier paragraph…

                                                                                      They are usability studies. They are deliberately designed to be as difficult as possible (you hide all the documentation) in order to get results.

                                                                                      Sure would be nice if you had documented evidence of that intuitiveness, but it seems the author has a grudge against usability studies.

                                                                                      EFAIL turned out to be a kind of a media hoax against PGP

                                                                                      EFAIL was a vulnerability in a program attempting to automate usage of PGP. This failed for predictable reasons, because you can’t automate usage of PGP, therefore any vulnerability from any such attempted automation is not the fault of PGP.

                                                                                      1. 2

                                                                                        Yes, I have a grudge in general against software that makes it impossible for the user to automate it.

                                                                                        1. 2

                                                                                          EFAIL was just programs trying to decrypt everything stupidly without parsing or considering message limits. It wasn’t because you can’t usage of PGP (you totally can), but because the program that doing it was written in incredibly stupid ways, dare I say without any security considerations.

                                                                                          1. 3

                                                                                            It’s not just the implementation that was erroneous. The Efail work identified various protocol bugs in gpg too.

                                                                                        1. 3

                                                                                          Expensive evaluation: Evaluation is slow and consumes massive amounts of memory. I would often restart evaluations because of memory exhaustion.

                                                                                          The official Nix binaries have serious code quality issues in the evaluator.

                                                                                          1. 5

                                                                                            I see a lot of posts on Firefox vs Chrome (or in this case Chromium) and it always seems to be people lobbying for others to use Firefox for any number of moral or security reasons. The problem that I see with a lot of this is that Firefox just isn’t as good of a user experience as Chromium-based browsers. Maybe Mozilla has the best intentions as a company, but if their product is subjectively worse, there’s nothing you can really do.

                                                                                            I’ve personally tried going back to Firefox multiple times and it doesn’t fulfill what I need, so I inevitably switch back to Vivaldi.

                                                                                            1. 10

                                                                                              This is really subjective. I tried using ungoogled-chromium but switched back to Firefox. I used Vivaldi for a while but switched to Firefox as well. Before I was using the fork of Firefox called Pale Moon but I got concerned with the lack of updates (due to how small is the team).

                                                                                              1. 2

                                                                                                Sure it is, but almost 80% of the world is using a chromium browser right now and Firefox is stagnant at best, slowly losing ground. Firefox even benefits from being around longer, having a ton of good will, and some name recognition and it still can’t gain market.

                                                                                                1. 8

                                                                                                  It also didn’t get advertised everytime you visit Google from another browser. It also isn’t installed by default on every Android phone.

                                                                                                  1. 8

                                                                                                    Firefox also isn’t installed by default by a bunch of PC vendors.

                                                                                                    1. 1

                                                                                                      Firefox already had its brand established for years before that happened. It’s also worth noting that Microsoft ships with its browser (which is now a Chromium variant, but wasn’t until recently) and doesn’t even use Google as the search engine, so the vast majority of new users don’t start with a browser that’s going directly to google to even see that message.

                                                                                                      1. 2

                                                                                                        And yet they start with a browser and why replace something if what you have already works discounting those pesky moral reasons as if those are not worth anything.

                                                                                                    2. 4

                                                                                                      Among technical users who understand browsers, sure, you might choose a browser on subjective grounds like the UX you prefer. (Disclaimer: I prefer the UX of Firefox, and happily use it just fine.)

                                                                                                      Most people do not know what a browser even is. They search for things on Google and install the “website opener” from Google (Chrome) because that’s what Google tells you to do at every opportunity if you are using any other browser.

                                                                                                      When some players have a soap box to scream about their option every minute and others do not, it will never matter how good the UX of Firefox is. There’s no way to compete with endless free marketing to people who largely don’t know the difference.

                                                                                                      1. 1

                                                                                                        If that were the case, people would switch back to Edge and Safari because both Windows and MacOS ask you to switch back, try it out again, etc every so often.

                                                                                                        The UX of firefox is ok (they keep ripping off the UI of Opera/Vivaldi though fwiw and have been doing so forever), but it functionally does not work in many cases where it should. Or it behaves oddly. Also, from a pure developer perspective, their dev tools are inferior to what has come out of the chromium project. They used to have the lead in that with Firebug, too, but they get outpaced.

                                                                                                  2. 2

                                                                                                    Yeah, I switched to Firefox recently and my computer has been idling high ever since. Any remotely complicated site being left as the foreground tab seems to be the culprit.

                                                                                                  1. 5

                                                                                                    Why does Richard Stallman have anything to say about a non-GPL tool used to fetch files from proprietary services?

                                                                                                    1. 18

                                                                                                      Why do you have an impression that rms keeps his public expressions of opinion limited to a narrow topic?

                                                                                                      1. 13

                                                                                                        GPL is a tool serving his more general copyleft philosophy. There’s plenty of interesting material in the youtube-dl takedown story, from a copyleft perspective.

                                                                                                      1. 7

                                                                                                        I am curious, is this illegal in some way? They are effectively on purpose introducing bugs or security holes into a ton of computer systems including ones that are run by various government agencies and they admit openly to doing it.

                                                                                                        1. 7

                                                                                                          Probably not illegal, but there is no evidence of ethics approval. Chances are they can’t get ethics on it.

                                                                                                          I’ve spoken to a couple of academics about this case and they can’t quite believe someone is trying to pull this in the name of research.

                                                                                                          Also, looking at the funding sources they cite, they seem pretty out of bounds on that front:

                                                                                                          https://nsf.gov/awardsearch/showAward?AWD_ID=1931208 https://nsf.gov/awardsearch/showAward?AWD_ID=1815621

                                                                                                          1. 5

                                                                                                            I think it’s borderline. Pen-testing is legal, and it’s generally done “on the sly” but with management’s approval.

                                                                                                            1. 18

                                                                                                              I don’t think this is pen-testing, their code reached the stable trees supposedly. Once that happens they actually introduced bugs and security issues and potentially compromised various systems. This is not pen-testing anymore.

                                                                                                              https://lore.kernel.org/linux-nfs/CADVatmNgU7t-Co84tSS6VW=3NcPu=17qyVyEEtVMVR_g51Ma6Q@mail.gmail.com/

                                                                                                              1. 1

                                                                                                                Whether their code reached stable trees is irrelevant to whether or not it’s pen-testing - you can just as easily imagine a pen-tester accidentally leaving a back-door in a system after their contract has expired. Criminal negligence? Yes. Evidence of an unethical practice in the first place? Not in the slightest.

                                                                                                                Similarly, the researchers said that, as soon as one of their patches was accepted, they would immediately notify the tree maintainer. If they did that, and the maintainer was paying attention, the patch would never make it to a stable tree.

                                                                                                                Whether someone is ethical or not is completely unrelated to its outcome.

                                                                                                              2. 2

                                                                                                                Pentesting comes with contracts and project plans signed by both the tester(s) and the company main stakeholder(s). So, no it’s not at all the same.

                                                                                                              3. 4

                                                                                                                Probably not, opensource is “no warranty” all the down.

                                                                                                                1. 1

                                                                                                                  Almost certainly… For instance the following seems appropriate.

                                                                                                                  18 U.S. Code § 2154 - Production of defective war material, war premises, or war utilities

                                                                                                                  Whoever, when the United States is at war, or in times of national emergency as declared by the President or by the Congress, […] with reason to believe that his act may injure, interfere with, or obstruct the United States or any associate nation in preparing for or carrying on the war or defense activities, willfully makes, constructs, or causes to be made or constructed in a defective manner, or attempts to make, construct, or cause to be made or constructed in a defective manner any war material, war premises or war utilities, or any tool, implement, machine, utensil, or receptacle used or employed in making, producing, manufacturing, or repairing any such war material, war premises or war utilities, shall be fined under this title or imprisoned not more than thirty years, or both

                                                                                                                  Probably also various crimes relating to fraud…

                                                                                                                  1. 8

                                                                                                                    when the United States is at war,

                                                                                                                    Except it’s not, so, this is not appropriated at all.

                                                                                                                    There’s no contract, no relationship, no agreement at all between an opensource contributor and the project they contribute to. At most some sort of contributor agreement that is usually in there only for handling patents. When someone submits a patch they’re making absolutely no legal promises as for the quality of said patch, and this propagates all the way to whoever uses the software. The licenses don’t say THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND for nothing. Sure, the US army or whatever might use Linux, but they do it at their own peril.

                                                                                                                    Now, they might get in trouble for being sketchy about the ethical approval and stuff, but that will only get them in professional trouble at most, like loosing their jobs.

                                                                                                                    1. 3

                                                                                                                      You missed the second half of the disjunction

                                                                                                                      or in times of national emergency as declared by the President or by the Congress,

                                                                                                                      This clause is true… many times over https://en.m.wikipedia.org/wiki/List_of_national_emergencies_in_the_United_States

                                                                                                                      Edit: The US army does not do it at their own peril against actively malicious activities. Civil contracts do not override statutory law, rather the other way around.

                                                                                                                      1. 2

                                                                                                                        Hmm, yeah, I stand corrected (partially, at least).

                                                                                                                        However, the law you’re quoting says war stuff or stuff used to make war stuff. I’m not even sure software would qualify as stuff, as described in there. But yeah, I’m less sure they are not screwed now. Also, from the names, they might not be US citizens, which could make things worse.

                                                                                                                        That said, I’m somewhat skeptical anyone would pursue this kind of legal action.

                                                                                                                        1. 7

                                                                                                                          The definition of what’s protected here is really broad. Is the linux kernel used a tool to help operate the telecommunications infrastructure for the company making uniforms for the military? If so it’s protected.

                                                                                                                          It’s almost like it was written for actual times of war, not this nonsense of a constant 30 national emergencies going on. Blame congress.

                                                                                                                          I agree it’s unlikely to be prosecuted, unless there is significant damage attributable to the act of sabotage (someone deploys some ransomware to a hospital that exploits something they did, for instance), or someone in power decides that the act of sabotage’s main purpose was actually sabotage not getting papers… If it is prosecuted I also think it’s likely that they’ll find some more minor fraud related crime to actually charge… I just found this one by googling “sabotage, us law”.

                                                                                                                          1. 3

                                                                                                                            There’s what the law says (or can be construed to say) and what a court will actually accept. I think a lawyer would have a hard time convincing a jury that a silly research paper was war sabotage.

                                                                                                                            1. 3

                                                                                                                              I wish I had your faith in the system. I think a lot of this stuff depends on whether prosecutors choose to make an example of the person. I can’t see that happening here; I very much doubt that the US federal government sees its own power threatened by this irresponsible research. However, if you look at the history, there are examples that I find similarly absurd which did lead to convictions. The differentiating factor seems to not be any genuine legal distinction, but simply whether prosecutors want to go all-out.

                                                                                                                              Furthermore, the ones the public knows about are the ones that happened in regular courts. Decisions by FISA courts or by military tribunals do not receive the same scrutiny, and thus we must assume the injustice is even greater in those venues.

                                                                                                                              1. 1

                                                                                                                                I don’t deny that unjust laws are often enforced, despite jury trial, I just think that in this case it would be pretty unlikely for that to happen.

                                                                                                                                I think the state/ruling class is more likely to abuse its power when it is threatened, embarassed (journalists, whistleblowers (Wikileaks), minor hackers) or when there is the opportunity to harm an out-group or political opponent (e.g. non-dominant ethnic groups, leftist movements, sometimes extreme right-wing groups); and I don’t think any of those really apply here.

                                                                                                                                1. 2

                                                                                                                                  I apologize for the belated reply. I do agree with all of that.

                                                                                                                              2. 1

                                                                                                                                Feels like a case ripe for independent reinvention of jury nullification.

                                                                                                                  1. 1

                                                                                                                    Glad to see some of the lessons from cluster scale filesystems slowly leaking into open source data storage products.

                                                                                                                    1. 4

                                                                                                                      FWIW, Swift has this too. It’s not limited to generics; in Swift you can define multiple normal functions with the same parameters (if any) but different return types, and the compiler will do it’s best to choose the right one.

                                                                                                                      On the downside, it must get complicated for the compiler to solve these puzzles, so I’m sure this feature contributes to both Rust’s and Swift’s infamously slow compile times.

                                                                                                                      1. 5

                                                                                                                        Rust’s compile times aren’t due to issues like selecting the right return type, but rather for things like code generation. Monomorphization as a strategy for implementing statically-dispatched parametric polymorphism requires the generation of distinct copies of each generic type or function based on the concrete types it’s actually used with. The time to perform this code generation and update call sites can be long. Monomorphization can also lead to code bloat, though there are techniques to manage that bloat.

                                                                                                                        I don’t know as much about Swift, but I doubt that type resolution is a major cause of slow compilation.

                                                                                                                        1. 3

                                                                                                                          I remember at least one case where the type resolution was a major compilation time slowdown, it was checking 11k+ alternatives for a common function before it was fixed.

                                                                                                                          1. 2

                                                                                                                            Your link about using an inner function to limit the code generated by monomorphization is super interesting.

                                                                                                                            1. 2

                                                                                                                              Glad you like it! I wrote that post.

                                                                                                                        1. 17

                                                                                                                          Oh, like outage post-mortems?

                                                                                                                          I second this, good idea.

                                                                                                                          (could you dig up some example stories from the past to flesh out the tag request?)

                                                                                                                            1. 4

                                                                                                                              Thank you for spending cycles on that!

                                                                                                                              I think that makes a really compelling case for @pushcx et al. to consider.

                                                                                                                              1. 3

                                                                                                                                I think so too. I don’t see this as fitting in very well with any of the existing tags, and it feels very in the Lobsters spirit to me.

                                                                                                                              2. 1

                                                                                                                                These are all outages. “Post-mortem” and “incident” don’t adequately express that it’s network/infra related imo. Maybe “services” covers these, though quite broad too.

                                                                                                                            1. 7

                                                                                                                              I have wondered this for so long!

                                                                                                                              1. 3

                                                                                                                                I have a faint memory that one of the really, really old CVEs was for this. A privileged script that expected its arguments to be file names, I think, and could be made to do Wrong Things by passing in shell metacharacters or -.

                                                                                                                                1. 10

                                                                                                                                  People (rightly) talk a lot about the security implications of software being written in memory-unsafe languages like C. But, while there’s a lot of talk about the gotchas in shell programming, there’s shockingly little talk about the security implications of having so much software written in a language where it’s almost impossible to handle files correctly and almost impossible to handle strings correctly,

                                                                                                                                  1. 7

                                                                                                                                    I think that if a language’s safest way to compare strings uses syntax as weird "x$a" = "x$b", that’s a warning sign with letters big enough to read from space.

                                                                                                                                    The sign reads do not use this language to write code to be run by strangers, and if there’s a footnote, the footnote says “this is a fine language to write a plugin for git bisect and that kind of one-offs, but not for writing things to be run by stranger, okay? you understand now?”

                                                                                                                                    1. 3

                                                                                                                                      Yeah, I agree. Another interesting challenge is to iterate over all the files in a directory, correctly, and without doing the actual loop in a subprocess; it’s probably possible, but most people’s first 3 attempts will probably be dangerously broken.

                                                                                                                                      I agree that shell is a fine language for tiny one-off things, but I believe it’s being used way more broadly than that. I just ran a find /usr -name '*.sh' | xargs cloc [1] on my system, and found 114501 lines of shell across 1050 files. I don’t have a great level of confidence that none of those shell scripts ever consume untrusted input.

                                                                                                                                      [1] As an interesting footnote, find /usr -name '*.sh' | xargs cloc is incorrect; it won’t work if files contain whitespace, quotes or backslashes. The “correct” (AFAIK) command would be find /usr -name '*.sh' -print0 | xargs -0 cloc. I sure hope nobody has ever made that mistake in a context where files may contain “weird” characters! Also, that approach only works for iterating over a relatively small number of files; how many is dependent on your particular POSIX system!

                                                                                                                                      1. 4

                                                                                                                                        It also ignores the staggering number of shell scripts that are involved in the init process that aren’t named *.sh!

                                                                                                                                    2. 3

                                                                                                                                      Bash is like glue, only a fool would make a whole building out of it.

                                                                                                                                1. 1

                                                                                                                                  Performing IRC support for Minecraft mod authors, followed by an automatic error diagnosis system in a custom Minecraft launcher. It would tell you exactly how you screwed up your mod installation.

                                                                                                                                  1. 24

                                                                                                                                    Despite not having any kernel developers on-staff, Ars was able to verify at least some of Donenfeld’s claims directly, quickly, and without external assistance.

                                                                                                                                    Extremely important paragraph IMO. Why don’t we see things like this in other programming reporting?

                                                                                                                                    1. 16

                                                                                                                                      Because reporters earning $40k/yr don’t typically have the same skill set as a developer making $150k? If you know how to use grep well, you’ve got the start of a newer, higher paying career.

                                                                                                                                    1. 2

                                                                                                                                      I’ve not played Factorio yet but how long does a full run take on average? Or is it just time boxed regardless? Lol.

                                                                                                                                      1. 3

                                                                                                                                        There’s an achievement for doing it in under 8 hours (there are several finish-time achievements but the 8-hour achieve “there is no spoon” is the hardest), but realistically a noon will take a LOT longer than that for their first time. I’d guess 100+ hours, although that’s just playing the game for fun and without specifically rushing to rocket-launch.

                                                                                                                                        1. 2

                                                                                                                                          My first run was 100+ hours; speedrunners finish it in a little over 2.5 hours on default settings.

                                                                                                                                          1. 2

                                                                                                                                            It really depends on how hard you rush towards launching the rocket - the “game over” condition (quotes there because you can play beyond launching a rocket).

                                                                                                                                            You could do it in a few hours if you rush and have an idea what you need to do. First time with no guides will probably be longer. Speedrunners can do it in about an hour - edit: hour and a half.

                                                                                                                                            1. 5

                                                                                                                                              A reasonably knowledgable pair of players, going in with a good premade plan, can launch a rocket in 3 hours. Default settings.

                                                                                                                                            2. 1

                                                                                                                                              My first play through was 40+ hours

                                                                                                                                              1. 1

                                                                                                                                                Personally I have played maybe 3 or 4 times and I always gave up before launching the rocket, after quite a few hours. I’m definitely not good at Factorio but this game is both quite difficult and truly great.

                                                                                                                                                1. 1

                                                                                                                                                  I’ve dabbled in it for years, when 1.0 came out I finally did a full play through and it took around 30 hours.