Threads for carlmjohnson

  1. 8

    No client-side router, so no need to implement focus management, scroll restoration, etc.

    Don’t forget screen reader accessibility. A client-side router needs to announce (usually through an invisible ARIA live region) when it has navigated to a new page. This announcement can’t entirely replicate the experience that a screen reader user has when real browser navigation happens. So in this area, too, a SPA has to poorly reimplement what’s already built into the browser. For this reason alone, I’ve never shipped a SPA.

    1. 1

      Hmm, I hadn’t really thought about that issue. Thinking about something like Gmail, wouldn’t the ideal audio implementation be something more like a phone tree: “You have 5 new messages. The first message is from Sue Smith, read more? The second message is from Jane Doe, read more?” In general, I think it’s sort of a shame that people aren’t making alternative audio only implementations of webpages. There’s no reason I couldn’t be in a car and say, “Hey Dingus, read Lobsters,” and have it say, “Lobste dot rs. Top story: More Thoughts On SPAs. Read more? Next story: Why I built an alternative audio interface to Lobsters. Read more?” etc. So far though, screen readers are really just helpers for the visual experience, and not experiences in their own right.

      1. 5

        In general, I think it’s sort of a shame that people aren’t making alternative audio only implementations of webpages.

        This is tangential, but I think this sentiment is common enough that it’s worth addressing.

        We disabled minorities, e.g. blind people, are concerned with making sure that we get access to as much information and functionality as possible. We know that most providers aren’t going to design specifically for us; they’re going to design for the majority who have whatever ability we lack, usually without giving it a second thought. So ideally we want to automatically get access to the same applications, documents, etc. that are being provided to everyone else, with a minimum of extra effort specifically for us. Bringing this back to the original topic of discussion, this is why I feel that JavaScript-based navigation (as in SPAs) is a regression for accessibility by default. With real navigation, done by the browser, the application or framework developer doesn’t even have to think about accessibility (for that specific function); the browser and screen reader take care of it. But when JavaScript code takes over that function of the browser, it has to poorly replicate what the browser and screen reader were already doing.

        To finish addressing your comment, an interface designed specifically for audio output sounds nice in principle, but the reality is that even if it gets developed, it probably won’t be kept perfectly in sync with the GUI that everyone else is using. And an audio-specific interface doesn’t even serve all blind people; for example, deafblind people need to use a braille device. An interface specifically optimized for audio is certainly a nice luxury for people who want to do a small number of tasks in a restricted environment, e.g. in the car. But for blind people who should have equal access to everything that sighted people can access, it’s no substitute for grafting a screen reader onto a GUI, as clunky as that is.

        1.  

          Yeah, I’m not imagining this as a replacement for screen reader technology. It’s just something new that should exist because it would be useful to lots of people. For sighted people, there are tons of scenarios where we can’t use our eyes because we’re busy walking, driving, doing dishes, light childcare, whatever. Just speaking personally, I consume an order of magnitude more podcasts than videos because podcasts are content I can enjoy while doing something else, but TV, movies, etc. require more engagement. Unfortunately, capitalism is always going prioritize the needs of the majority over the needs of minorities, but on the positive side, there are so many scenarios where an audio interface would be helpful, it’s a huge market that if it ever were tapped into, it could throw off benefits for other communities as well.

        2. 2

          The best breakdown of this problem that I’ve read is this article by Marcy Sutton.

          To be fair though, I think there is some work underway to solve this problem in the experimental Navigation API.

      1. 2

        I was thinking about this and I think I have a nice minimal example of this behavior:

        Imagine you have a program where the user controls a point on a 2D grid. The user always starts at (0, 0). They can move left, right, up, or down. This is a very simple program, but after a long enough time line it could start to misbehave. For example, let’s say you represent the x and y values with signed 32 bit integers and overflow in your language is undefined. Most runs will never have any problems, but if someone races to an edge they could trigger undefined behavior on integer overflow. The user can’t tell what’s going on. Maybe it maps to their character in a video game and they teleport to a completely different part of the world. They restart the game, go back to origin and everything is fine.

        1. 8

          In Legend of Zelda: Breathe of the Wild, there’s a gameplay mechanic where occasionally the “blood moon” will rise and all your defeated enemies will come back to life. What’s actually happening is the game is resetting to a known good state, but they make it seem relevant in game.

          1. 1

            Is that really the intent? If so, that’s amazing! I love how video game developers are able to pull the wool over our eyes. Reminds me of classic Hollywood illusions. Trust nothing!

            1. 5

              Wing Commander for DOS would crash after exiting the game, before returning to the DOS prompt, with an error message displayed on the screen. The devs just patched the error string to say “Thanks for playing Wing Commander!”

          1. 39

            It’s frankly kind of fascinating that something made by Google would even let you think about the word “union” when using it.

            Lol.

            1. 3

              It’s frankly kind of fascinating that something made by Google would even let you think about the word “union” when using it.

              Can someone explain the joke for me? :’(

                1. 2

                  Hah! Thanks for spelling it out.

            1. 39

              A novice was trying to fix a broken Lisp machine by turning the power off and on.

              Knight, seeing what the student was doing, spoke sternly: “You cannot fix a machine by just power-cycling it with no understanding of what is going wrong.”

              Knight turned the machine off and on.

              The machine worked.

              1. 22

                It sounds like a joke but I have literally done this, for work. Not that often, but definitely more than once or twice.

                If I’m feeling confident I first rest my hands on the machine and intone “The power of Knuth compels you, be healed!”

                1. 6

                  Somewhere in recent historiy a coworker reported the unexpectedly early death of a small handful of machines in a datacenter that we rarely have a person visit. All of them were redundant cattle so it was mostly an accounting loss and an eventual cleanup task.

                  They would have been part of a list of machines to get upgrades, and managed to appear on the list of machines that failed to upgrade, so I went to check them out. No ping to the primary address. The BMC pinged, though, so I asked it to power cycle, and then watched the serial console. The machine booted properly.

                  All of them in that suspect group came up, in fact. They have each made several reboots since then without issue.

                  I conclude that it is possible to do this remotely, no blood sacrifices required.

                  1. 0

                    <3

                1. 1

                  Git has exhausted its potential in my eyes. God be merciful, I’ll write my own vcs. For myself. Maybe not even going to make it publicly available, but only to those who actually get it.

                  1. 2

                    Good luck! You’ll be following in the footsteps of many dead or antiquated VCS systems, like (off the top of my head…) Fossil, BitKeeper, Mercurial, Bazaar, and Darcs.

                    1. 1

                      I sort of want https://pijul.org/ to break out and become the next big thing, but I worry it’s not better enough to overthrow the consensus choice.

                    2. 2

                      You could also write a new porcelain on top of git. git’s internals are a pretty straightforward set of primitives about a content addressable file system and commits.

                    1. 6

                      Beware when you have conflicts in the dependency files (package.json, go.mod, requirements.txt…). Do not remove dependencies until you are sure that they are not needed at the very end of the merge. Add any dependency suggested during the conflict resolution and decide at the end if it is necessary.

                      Or just create file .gitattributes with:

                      your.lockfile merge=binary
                      

                      And then it will only mark a file as conflicted without putting conflict markers. It will allow you to simply your-dep-tool update to update the lock file to newest configuration. This makes working with lock files much neater and cleaner.

                      1. 1

                        Wow, I’ve never heard of that. That’s a great tip!

                        1. 1

                          This one is a great tip! This aligns with the recommendation of regenerating files.

                        1. 25

                          There is one important reason for using big endian that has been left out in the article: When specifying a binary protocol/file format, using big endian makes it much more likely that it’s implemented correctly by others: Most systems are little endian nowadays, so it’s likely that people won’t bother with proper endian conversion during implementation.

                          I can also confirm this with personal experience: I explicitly chose big endian integer fields for my image file format farbfeld and got numerous complaints from people about why I chose big over little endian. They argued that given most systems are little endian anyway such a conversion is wasteful (I’d argue this factor is negligible). After further discussion, I found out that they were mapping files directly to memory, and with even a small oversight, if I had specified little endian values, the code would’ve worked as is on most systems, only to drastically fail on big endian machines.

                          I think this is an interesting aspect to keep in mind.

                          1. 12

                            That’s perverse as heck and I love it. XD “Why did you do it this weird way, you could make it less work” “The work would always be there, you just don’t get to ignore it now” is an approach I have deep sympathy with.

                            1. 1

                              Exactly, it’s all about paying off debt now rather than down the road.

                              1. 2

                                Yeah. I wonder if there’s a way to do this by having some kind of conformance test suite rather than booby-trapping the specification? Though for a file format the conformance suite usually consists of a bunch of somewhat-degenerate example files with expected output they should produce, and if you want people to actually use it to vet their file reader/writer implementations you’ll have a hard time saying “run this on a big-endian VM of some kind”…

                            2. 8

                              In JSON APIs, I sometimes will deliberately use “kebab-case-keys” to force the clients to write a proper validator on the other end instead of doing response.camelCaseKey and just hoping its valid. :-)

                              1. 7

                                It’s a shame that this is necessary because it’s a file format design decision to work around problems in specific languages. If I were parsing your file in Erlang, for example, then I’d do binary pattern matching which takes an explicit endian in the pattern description. My code would be trivially portable. Doing the same in C would require a load of manual byte swapping. Doing the same in C++ would probably make me just lift the endian wrappers from LLD. Even if I mmap the file, as long as I declared the field as the type of the correct endian, it would be fine. Similarly with Rust, I could use a fixed-layout structure containing a type that does byte swapping on access to define the header fields and still have the right thing happen.

                                Things like this make me realise that C has probably been making the world a worse place for long enough.

                                1. 4

                                  POSIX offers the ntoh*() and hton*() functions for that purpose. It’s not that difficult.

                                  1. 2

                                    It’s still tedious, and if something’s tedious versus an “easy” way that will blow your foot off in a slightly different situation, C programmers will pick the latter.

                                    1. 1

                                      What could be simpler than a single function call?

                                      1. 2

                                        Not having to do anything. In C++, for example, you’d declare the field as something like a BigEndian<uint32_t>. The BigEndian<T> template would have an implicit cast-to-T operator containing an if constexpr that either did byte swapping or didn’t, based on the host platform. LittleEndian<T> would be similarly implemented (or, more commonly, both would just be using directives that expanded to T or ByteSwapped<T> depending on the current architecture). You declare a struct representing your data with these types and then never think about it again. In contrast, the C approach requires a function call for every field that you have to remember everwhere, or requires you to do a single byte-swap-everything pass to get it right.

                                        Similarly, in Erlang, you just write the /big or /little modifier in your pattern matches and everything falls out. C is the most verbose and error prone language that I’ve used for this kind of thing. Last time I had to write an implementation of a protocol that used a big-endian wire format, the byte-swapping bits of the C implementation were larger than the total Erlang implementation.

                                        1. 1

                                          Referencing a field or array member directly.

                                  2. 3

                                    Thanks for the explanation! I was like /o\ when i saw that farbfeld is using big endian, and i still think it’s the wrong decision. But i can see reason in your decision and it’s less of a “why?!” to me now and more a “okay, seems like we value different things” 👍

                                    farbfeld is a cool project and i should add support for it to zigimg for more widespread support

                                    1. 2

                                      Completely agree. I’m working a lot with parsing big endian data right now, and had it been little endian I wouldn’t have given nearly as much thought to my implementation. Now my code will work properly regardless of the endianness.

                                      1. 2

                                        I experienced the opposite at work. There’s a project at work that started out life on a big endian system (SPARC for the curious), and it was my work that made it possible to use a little endian system. It made the project more portable, and when we finally move off of SPARC to Linux, it should just work [1].

                                        [1] It will. We actually develop and test now on Linux (cheaper than getting everyone a SPARCstation).

                                      1. 31

                                        its release philosophy is supposed to avoid what I call “the problem with Python”: your code stops working if you don’t actively keep up with the latest version of the language.

                                        This is a very real problem with the Python and Node ecosystems.

                                        1. 16

                                          I’m going to be grumpy and ask what this “problem” is supposed to mean, exactly. I can deploy, say, a Python application on a particular version of Python and a particular operating system today, and then walk away for years, and as long as I pay the hosting bill there is no technical reason why it would suddenly stop working. There’s no secret kill switch in Python that will say “ah-ha, it’s been too long since we made you upgrade, now the interpreter will refuse to start!”

                                          So what people always actually mean when they say things like this is that they want to keep actively developing their code but have everybody else stand still forever, so that they can permanently avoid platform upgrades but also the language and ecosystem will never leave them behind. So the real “problem” is that one day nobody else will be willing to provide further bug and security fixes (free or perhaps even paid) for the specific combination of language/libraries/operating system I initially chose to build my app with, and on that day I have to choose between upgrading to a new combination, or doing that maintenance myself, or going without such maintenance entirely.

                                          And although I’ve seen a lot of claims, I’ve seen no evidence as yet that Rust has actually solved this problem — the editions system is still young enough that the Rust community has not yet begun to feel the pain and cost of what it committed them to. “Stability without stagnation” is a nice slogan but historically has ranged from extremely difficult to downright impossible to achieve.

                                          1. 16

                                            “Stability without stagnation” is a nice slogan but historically has ranged from extremely difficult to downright impossible to achieve.

                                            You just don’t make breaking changes. Add new APIs but don’t take away old ones. Go 1 has been stable for 10 years now. That means there are some ugly APIs in the standard library and some otherwise redundant bits, but it’s been fine. It hasn’t stopped them from adding major new features. Similarly, JavaScript in the browser only rolls forward and is great. Again, some APIs suck, but you can just ignore them for the most part and use the good versions. I’m not as familiar with the Linux kernel, but my impression there is that Linus’s law is you don’t break userland.

                                            Most breaking changes are gratuitous. They make things a little nicer for the core developers and shove the work of repair out to everyone who uses their work. I understand why it happens, but I reserve the right to be grumpy about it, especially because I have the experience of working in ecosystems (Go, the browser) that don’t break, so I am very annoyed by ecosystems that do (NPM, Python).

                                            1. 15

                                              I’ll be up-front. My stance on breaking changes is that there are two types of projects:

                                              1. Those which have decided to accept they are an inevitable fact of software development, and so have committed to the process of handling them, and
                                              2. Those which haven’t yet.

                                              And remember that we are talking not just about core language/standard library, but also ecosystems. Go has already effectively broken on this — the “rename your module to include /v2” hack is an admission of defeat, and allows the previous version to lapse into a non-maintained status. Which in turn means that sooner or later you will have to make the choice I talked about (upgrade, or do maintenance yourself, or go without maintenance).

                                              And Rust has had breaking changes built into the ecosystem from the beginning. The Cargo/crates ecosystem isn’t built around every crate having to maintain eternal backwards-compatibility, it’s built on semantic versioning. If I publish version 1.0 of a crate today, I can publish 2.0 with breaking changes any time I want and stop maintaining the 1.x series, leaving users of it stranded.

                                              So even if Rust editions succeed as a way of preserving compatibility of the core language with no ecosystem splits and no “stagnation”, which I strongly doubt in the long term, the ecosystem has already given up, and in fact gave up basically immediately. It has “the Python problem” already, and the only real option is to learn how to manage and adapt to change, not to insist that change is never permitted.

                                              (and of course my own experience is that the “problem” is wildly exaggerated compared to how it tends to impact projects in actual practice, but that’s another debate)

                                              1. 5

                                                I think it’s hard to talk about this rigorously because there’s definitely some selection bias at play — we don’t have information about all the internal projects out there that might be bogged down by breaking changes between interpreter versions, and they’re likely motivated by very different incentives than the ones that govern open source projects — and there’s likely survivorship bias at play too, in that we don’t hear about the projects that got burnt out on the maintenance burden those breaking changes induce.

                                                My anecdotal evidence is that I’ve worked at places with numerous Python projects bound to different, sometimes quite old, interpreter versions, and there just aren’t enough person-hours available to keep them all up to date, and updating them in the cases where it was truly necessary made for some real hassle. Even if you chalk that up to bad resource management, it’s still a pretty common situation for an organization to find itself in, and it’s reasonable to expect your tools to not punish you for having less than perfect operational discipline. In light of that, I think understanding it in this binary frame of either making breaking changes or not isn’t the most fruitful approach, because as you note it’s not realistic to expect that they never happen. But when they do happen, they cost, and I don’t think it’s unreasonable for an organization to weigh that total cost against their resources and decide against investing in the Python ecosystem. It’s not unreasonable to make the opposite choice either! I just don’t think that cost is trivial.

                                                1. 7

                                                  Even if you chalk that up to bad resource management, it’s still a pretty common situation for an organization to find itself in and it’s reasonable to expect your tools to not punish you for having less than perfect operational discipline.

                                                  Imagine 20 years ago saying this about a project that suffered because they lost some crucial files and it turned out they weren’t using any kind of version control system.

                                                  Because that’s basically how I feel about it. Regularly keeping dependencies, including language tooling/platform, up-to-date, needs to become table stakes for software-producing entities the way that version control has. I’ve seen this as a theme now at four different companies across more than a decade, and the solution is never to switch and pray that the next platform won’t change. The solution is always to make change an expected part of the process. It can be done, it can be done in a way that minimizes the overhead, and it produces much better results. I know because I have done it.

                                                  1. 3

                                                    Because that’s basically how I feel about it. Regularly keeping dependencies, including language tooling/platform, up-to-date, needs to become table stakes for software-producing entities the way that version control has.

                                                    I don’t believe this is what’s being disputed: it’s that this being a fact is precisely why it’s important for the platform to facilitate ease of maintenance to the best of its ability in that regard. Doing so allows even under-resourced teams to stay on top of the upgrade treadmill, which is more of my point in the bit you quoted: tools that induce less overhead are more resilient to the practical exigencies that organizations face. I guess we’ll have to agree to disagree about where the Python ecosystem sits on that spectrum.

                                                    1. 2

                                                      This sounds like the “don’t write bugs” school of thought to me. Yes, ideally anything that’s an operational concern will get ongoing maintenance. In the real world… 

                                                      More anecedata: my coworker built a small Python scraper that runs as a cron job to download some stuff from the web and upload it to an S3 bucket. My coworker left and I inherited the project. The cron job was no longer a high priority for the company, but we didn’t want to shut it off either. I couldn’t get it to run on my machine for a while because of the Python version problem. Eventually I got to the point where I could get it to run by using Python 3.6, IIRC, so that’s what it’s using to this day. Ideally, if I had time and resources I could have figured out why it was stuck and unstick it. (Something to do with Numpy, I think?) But things aren’t always ideal.

                                                      If someone has to have discipline and try to stick closer to the “don’t write bugs” school, who should it be: language creators or end developers? It’s easy for me to say language creators, but there are also more of us (end developers) than them (language creators). :-) ISTM that being an upstream brings a lot of responsibility, and one of those should be the knowledge that your choices multiply out by all the people depending on you: if you impose a 1 hour upgrade burden on the 1 million teams who depend on you, that’s 1 million hours, etc.

                                                      1. 1

                                                        Generalizing from anecdata and my own experience, the killer is any amount of falling behind. If something is not being actively maintained with dependency updates on at least a monthly and ideally a weekly cadence, it is a time bomb. In any language, on any platform. Because the longer you go without updating things, the more the pending updates pile up and the more work there will be to do once you do finally sit down and update (which for many projects, unfortunately, tends to be only when they are absolutely forced to start doing updates and not a moment sooner).

                                                        At my last employer I put in a lot of work on making the (Python) dependency management workflow as solid as I could manage with only the standard packaging tooling (which I believe you may have read about). But the other part of that was setting up dependabot to file PRs for all updates, not just security, to do so on a weekly basis, and to automate creation of Jira tickets every Monday to tell the team that owned a repository to go look at and apply their dependabot PRs. When you’re doing it on that kind of cadence it averages very little time to review and apply the updates, you find out immediately from CI on the dependabot PRs if something does have a breaking change so you can scope out the work to deal with it right then and there, and you never wind up in a situation where applying the one critical update you actually cared about takes weeks or months because of how much other stuff you let pile up in the meantime.

                                                        Meanwhile I still don’t think Python or its ecosystem are uniquely bad in terms of breaking changes. I also don’t think Go or Rust are anywhere near as good as the claims made for them. And the fact that this thread went so quickly from absolutist “no breaking changes ever” claims to basically people’s personal opinions that one language’s or ecosystem’s breaking changes are justified and tolerable while another’s aren’t really shows that the initial framing was bad and was more or less flamebait, and probably should not be used again.

                                                        1. 5

                                                          No, I still think you’re wrong. :-)

                                                          I agree that for a Python or Node project it is recommended to set up dependabot to keep up to date or else you have a ticking time bomb. However, a) that isn’t always practical and b) it doesn’t have to be like that. I routinely leave my Go projects unattended for years at a time, come back, upgrade the dependencies, and have zero problems with it.

                                                          Here is a small project last touched in 2017 that uses Go and Node: https://github.com/baltimore-sun-data/track-changes

                                                          Here is the full Terminal output of me getting it to build again with the most recent version of Go:

                                                          (Fri, May 20  08:56:09 PM) (master|✔)
                                                          $ go build .
                                                          go: cannot find main module, but found Gopkg.lock in /var/folders/p7/jc4qc9n94r3f6ylg0ssh1rq00000gs/T/tmp.S6ZYg4FX/track-changes
                                                                  to create a module there, run:
                                                                  go mod init
                                                          # status: 1 #
                                                          (Fri, May 20  08:56:27 PM) (master|✔)
                                                          $ go mod init github.com/baltimore-sun-data/track-changes
                                                          go: creating new go.mod: module github.com/baltimore-sun-data/track-changes
                                                          go: copying requirements from Gopkg.lock
                                                          go: to add module requirements and sums:
                                                                  go mod tidy
                                                          (Fri, May 20  08:57:00 PM) (master|…)
                                                          $ go mod tidy -v
                                                          go: finding module for package github.com/stretchr/testify/assert
                                                          go: finding module for package golang.org/x/text/unicode/norm
                                                          go: finding module for package golang.org/x/text/secure/bidirule
                                                          go: finding module for package golang.org/x/text/unicode/bidi
                                                          go: finding module for package golang.org/x/sync/errgroup
                                                          go: finding module for package github.com/stretchr/testify/suite
                                                          go: downloading golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
                                                          go: found github.com/stretchr/testify/assert in github.com/stretchr/testify v1.7.1
                                                          go: found github.com/stretchr/testify/suite in github.com/stretchr/testify v1.7.1
                                                          go: found golang.org/x/text/secure/bidirule in golang.org/x/text v0.3.7
                                                          go: found golang.org/x/text/unicode/bidi in golang.org/x/text v0.3.7
                                                          go: found golang.org/x/text/unicode/norm in golang.org/x/text v0.3.7
                                                          go: found golang.org/x/sync/errgroup in golang.org/x/sync v0.0.0-20220513210516-0976fa681c29
                                                          (Fri, May 20  08:57:10 PM) (master|…)
                                                          $ go build .
                                                          (Fri, May 20  08:57:18 PM) (master|…)
                                                          $ 
                                                          

                                                          As you can see, it took about a minute for me to get it building again. Note that this package predates the introduction of Go modules.

                                                          Let’s upgrade some packages:

                                                          (Fri, May 20  09:02:07 PM) (master|…)
                                                          $ go get -v -u ./...
                                                          go: downloading golang.org/x/net v0.0.0-20220520000938-2e3eb7b945c2
                                                          go: downloading cloud.google.com/go v0.101.1
                                                          go: downloading gopkg.in/Iwark/spreadsheet.v2 v2.0.0-20220412131121-41eea1483964
                                                          go: upgraded cloud.google.com/go v0.16.0 => v0.100.2
                                                          go: added cloud.google.com/go/compute v1.6.1
                                                          go: upgraded github.com/ChimeraCoder/anaconda v1.0.0 => v2.0.0+incompatible
                                                          go: upgraded github.com/andybalholm/cascadia v0.0.0-20161224141413-349dd0209470 => v1.3.1
                                                          go: upgraded github.com/garyburd/go-oauth v0.0.0-20171004151416-4cff9ef7b700 => v0.0.0-20180319155456-bca2e7f09a17
                                                          go: upgraded github.com/go-chi/chi v3.3.1+incompatible => v4.1.2+incompatible
                                                          go: upgraded github.com/golang/protobuf v0.0.0-20171113180720-1e59b77b52bf => v1.5.2
                                                          go: upgraded github.com/pkg/errors v0.8.0 => v0.9.1
                                                          go: upgraded golang.org/x/net v0.0.0-20171107184841-a337091b0525 => v0.0.0-20220520000938-2e3eb7b945c2
                                                          go: upgraded golang.org/x/oauth2 v0.0.0-20171117235251-f95fa95eaa93 => v0.0.0-20220411215720-9780585627b5
                                                          go: upgraded google.golang.org/appengine v1.0.0 => v1.6.7
                                                          go: added google.golang.org/protobuf v1.28.0
                                                          go: upgraded gopkg.in/Iwark/spreadsheet.v2 v2.0.0-20171026120407-29680c88e31d => v2.0.0-20220412131121-41eea1483964
                                                          (Fri, May 20  09:02:52 PM) (master|…)
                                                          $ go build .
                                                          # github.com/baltimore-sun-data/track-changes
                                                          ./handler.go:28:14: undefined: middleware.DefaultCompress
                                                          # status: 2 #
                                                          (Fri, May 20  09:02:58 PM) (master|…)
                                                          $ go doc middleware
                                                          package middleware // import "github.com/go-chi/chi/middleware"
                                                          
                                                          // snip
                                                          
                                                          (Fri, May 20  09:03:12 PM) (master|…)
                                                          $ go doc middleware.Compress
                                                          package middleware // import "github.com/go-chi/chi/middleware"
                                                          
                                                          func Compress(level int, types ...string) func(next http.Handler) http.Handler
                                                              Compress is a middleware that compresses response body of a given content
                                                              types to a data format based on Accept-Encoding request header. It uses a
                                                              given compression level.
                                                          
                                                              NOTE: make sure to set the Content-Type header on your response otherwise
                                                              this middleware will not compress the response body. For ex, in your handler
                                                              you should set w.Header().Set("Content-Type",
                                                              http.DetectContentType(yourBody)) or set it manually.
                                                          
                                                              Passing a compression level of 5 is sensible value
                                                          
                                                          (Fri, May 20  09:03:32 PM) (master|…)
                                                          $ subl .
                                                          (Fri, May 20  09:04:12 PM) (master|…)
                                                          $ go build .
                                                          (Fri, May 20  09:04:59 PM) (master|✚1…)
                                                          $
                                                          

                                                          Took about 3 minutes to upgrade the packages and fix the broken dependency (they renamed a middleware). Bear in mind that the upgrade I did deliberately did not try to upgrade past semantic version changes in its dependencies. Probably it would take another half hour or more if I wanted to chase down whatever breaking changes happened there.

                                                          Suffice it to say, yarn cannot even install its packages, and the last time I tried this stunt a couple of years ago, I got past that and then ran into a problem with webpack that I couldn’t easily solve.

                                                          Go is just a much more stable ecosystem than Node or Python. It’s not as stable as say browser JS, where one can reasonably expect working code to work until civilization collapses, but it’s fairly stable. And it’s not magic. If there were a communal expectation of this level of stability, it could exist everywhere. It’s a social value to keep things working in the Go ecosystem, and it’s not elsewhere.

                                                          1. 2

                                                            The other day I returned to a Python package I hadn’t touched in about a year. The actual Python dependencies portion of updating it was done in a few minutes: I updated the supported versions of Python to those currently supported by upstream, did the same for the supported versions of Django, and then had to change a whopping four lines of code, all in a unit-test file, to deal with a deprecation in Django that had finally been removed.

                                                            The entire remainder of getting it ready for a new release was fighting with CI — updating from v1 to v3 of the GitHub Actions tasks for Python, which I mostly did by copy/pasting from a package by someone else who I trust.

                                                            I mention this because while you have anecdotes about Go projects updating more or less seamlessly, I have just as many about Python projects, and other people in this thread have anecdotes about Go projects breaking in ways they found annoying.

                                                            All of which is to say that you should stop trying to extrapolate from your anecdata to “Go is stable and values stability, while Python is not and does not”, because it just ends up looking silly when other people show up with their anecdata. Python is not uniquely “unstable” and neither Go nor Rust are uniquely “stable”. At best, some projects are sometimes lucky enough that they can give the false impression of stability in the language/ecosystem, despite the fact that the language/ecosystem is always moving on. And that’s why I have said, over and over, that the thing to do is embrace and accept change and build processes around it. Otherwise, you’re likely to wake up one day to find out that what you thought was stable and unchanging was neither, and that you are in for a lot of trouble.

                                                            1. 3

                                                              When I get a chance, I thought of an equivalently old Python package for me to try updating. I’ll try to do it this weekend or next week.

                                                              But I just don’t buy this:

                                                              Python is not uniquely “unstable” and neither Go nor Rust are uniquely “stable”.

                                                              I don’t have experience with Rust, so I have no idea there. I do have years of working in Python, JavaScript, and Go and my experience is uniform: Python and JavaScript routinely have problems that make installing/updating take a workday, and Go does not. I’ve already given a lot of concrete examples, and I’m sure I could dig through my git history and find more. At a certain point, all I can say is this is my experience and if it’s not yours, great.

                                                              1. 2

                                                                You’re still missing the point I’m trying to make, though, because you keep diving for anecdotes to support your case, and I keep trying to remind you that if we allow generalizing from anecdotes then your own claims will get contradicted, because there are people who can bring similar anecdotes about languages like Go that you think don’t have this “problem”.

                                                                My stance here is and always has been that no language or ecosystem is free of the need to keep up with dependencies and no language or ecosystem is free from breaking changes. People in this comment thread have posted experiences with Go breaking on them and you’ve mostly just ignored that or disallowed generalizations from them, while insisting that your own anecdotes support generalizations, about the objective state of particular languages/ecosystems.

                                                                That is what I’m trying to get you to see, and trying to break you out of. No number of anecdotes one way or another will make your case for you, because the issue is not an insufficient number of presented anecdotes.

                                                                At a certain point, all I can say is this is my experience and if it’s not yours, great.

                                                                This is very close to where I’m trying to lead you, but

                                                                • You never actually just say that and stop — you always feel a need to throw on another anecdote and then insist that your experience generalizes to objective statements about particular languages/ecosystems, and that’s where it goes off the rails.
                                                                • You never really accept other people having experiences that don’t match yours, and thus disputing your generalizations. I don’t have the kinds of problems you do with Python. You don’t have the kinds of problems other people have had with Go. But I’m doing my best to acknowledge experiences other than my own when I say that no language/ecosystem is free of this issue: I expect that there will be people who do run into it in Python, and also in Go, and also in Rust, and also in every other language/ecosystem. You seem to be trying to erase the experiences of people who run into it in languages that you subjectively don’t believe have this problem, because it doesn’t fit the “this language has it, that language doesn’t” generalization you want to make.
                                                                1. 2

                                                                  your own claims will get contradicted, because there are people who can bring similar anecdotes about languages like Go that you think don’t have this “problem”.

                                                                  I have given a ton of anecdotes and done two experiments in support of my view. On the other side, there is your a priori assertion that all ecosystems have the same problems (but is it of the same magnitude?) and an unreadably long article by a pro-Rust troll. If other people have anecdotes about Go being hard to upgrade, I’m happy to read them (assuming they can get to a point in less than 10,000 words) and theorize about why someone else might have that problem when I don’t. But that hasn’t happened in this thread.

                                                                  1. 3

                                                                    Well, right here in this thread someone mentioned problems with upgrading in Go. But the way you and another user were trampling all criticism of Go with insults — “troll”, “clickbait”, and so on — literally drove that person out of the thread.

                                                                    I honestly don’t know what else to tell you. It seems very clear that you’re not prepared to hear anything that contradicts the narrative you’ve got going, so I guess I’ll bow out too since it’s pointless to continue trying to get you to acknowledge stuff that was literally right in front of you.

                                                                    1. 1

                                                                      I could never tell what the actual problems were based on the links posted by m0th were. They linked to long pieces with no summaries, so while I would love to comment, I cannot. Maybe it’s because they felt targeted by ad hominem. I have a different theory for why, which is that the criticisms were scattershot and not serious. Again, if they want to come back and provide a useable summary, great.

                                                                      1. 1

                                                                        And yet I’d bet anything that if you’d been given short concise statements of problems you’d dismiss them as being trivial or minor on those grounds. Like someone else already said, I simply cannot assume that you’re actually trying in good faith to engage with criticism of a thing you like; instead all I’ve seen you do is smear and deflect and dismiss without argument.

                                                                        1. 1

                                                                          If you call this “without argument” I don’t know what to say. I really feel that the “without argument” side is yours, and it is very frustrating to me, because you’re a writer whose work I respect which makes it very hard for me to let this go. But when you write things like “anecdotes don’t count”… What is a personal dev blog but anecdotes? I agree that supporters of language X can be vociferous and annoying, and Go is one such X. In that case of Go, the vociferous attitude comes from having been attacked as using a “bad language” by people like fasterthanlime and our own experience of initially thinking things like the v2 are dumb and then slowly seeing the benefits and defending them. I agree that my initial claim was a bit too glib in its characterization, but I stand by a less inflammatory version of the same idea. I don’t agree that anecdotes aren’t the data of software engineering, and I don’t agree it’s somehow impossible to characterize software ecosystems with the understanding that any generalization will always be at best partial and incomplete but nevertheless it’s better to have the generalization than not.

                                                                          1. 2

                                                                            People brought up criticism of Go. You didn’t engage with it or argue with the points made — you ignored them, or dismissed them as too long to be worth your time to read, or just outright insulted the author of one piece of Go criticism.

                                                                            It’s hard for me to see a way to take this as good faith. It appears that you like Go, which is fine! Same with Python: if you don’t like it, then don’t like it — that’s fine!

                                                                            What’s not fine is the double-standard “my anecdotes are generalizable to broad claims about the language/ecosystem as a whole, but other people’s anecdotes are not”. Which is basically what you’re doing. If your anecdotes about Python generalize, then so do mine and so do other people’s anecdotes about Go. Which would then contradict the claims you want to make, which is probably why you’re being so cagey about not allowing others’ anecdotes to generalize while insisting that yours do. But again it’s going to be, at least, extremely difficult to take that as a good-faith argument.

                                                                            1. 1

                                                                              When I engage with the criticism, I’m just dismissing it. If I don’t engage because I don’t have enough detail (or drowning in irrelevant details so I can’t tell why monotonic time is supposedly bad), I’m ignoring it. It’s no win.

                                                                              1. 2

                                                                                As far as I can tell the only “engagement” you’ve given to criticism of Go was the second paragraph in this comment, and I think that’s being charitable since it’s also possible to read as a “well, this breaking change didn’t count, and it just means Go is great instead of the greatest”. If I said Python’s stability guarantees are good but just “don’t go far enough”, I doubt you’d view it charitably.

                                                                                You have, on the other hand, repeatedly dismissed critiques both by users in this thread and linked to on other sites as being too long or too “scattershot” or “fair to handwave … away”. Again: if I tried pulling that sort of thing in defense of Python you would, I hope, call me on it. You’re doing it here in defense of Go. I’m calling you on it.

                                                                                1. 1

                                                                                  I wrote a long reply, decided to sleep on it, and I give up. You haven’t conceded any points. You’ve repeatedly accused me of bad faith. You’ve decided Python is as good as it gets and by definition nothing else can be better in some ways but not others. All I can say is I didn’t invent the phrase “the problem with Python”. Other people feel this way too. Maybe we’re wrong, and everything has the same problem to the same degree. I don’t think so though.

                                                                  2. 1

                                                                    You seem to be simultaneously saying there is nothing especially broken with python while defending the culture of constantly breaking changes and saying it is inevitable. I think your attitude sums up the problem, there are a lot of enablers.

                                                                    1. 3

                                                                      This thread started out with an accusation that there is a problem that uniquely exists in certain languages, and does not exist at all in others. People were very confidently stating not that the breaking changes in Go are less frequent, or less annoying, or more justified — people were very confidently stating that breaking changes simply do not exist at all in Go.

                                                                      Don’t believe me? Here, and a lot of the rest of this sub-thread is people trying to quibble about “oh well that was just a change to (thing that shouldn’t count)” or explain “well these changes were justified and tolerable while those other languages’ changes aren’t” in order to somehow cling to the notion that Go is a bastion of perfect stable compatibility, even in the face of solid evidence that it isn’t.

                                                                      And I’m sorry if people don’t like to hear it, but I’ve just gotta call bullshit on that. Every language and ecosystem has breaking changes. There is no magic in Go that makes it somehow unchanging and perfectly compatible forever, nor is there any magic in the ecosystem that somehow makes all maintainers good stewards who never ever make unjustified changes.

                                                                      Still, people seem to be wildly exaggerating both the frequency of breaking changes in the languages they want to criticize, while minimizing for the languages they want to praise. It’s very human and very subjective, and very not a good way to have a reasoned discussion about this.

                                                                      Especially when it’s coupled with very obvious bad-faith tactics like the way critics of Go keep being dismissed or even smeared in this thread.

                                                                      If you dislike Python, then by all means dislike it. There are things I dislike about it. But there’s way too much in this thread, and in our industry, of people being unable to handle anything other than extremes — something is either 100% good or 0%, either completely perfectly backwards-compatible always or never — and of very clearly contradicting themselves and making really bad arguments to try to justify their subjective dislikes. Just come out and say you don’t like a thing and move on. You don’t also have to prove that it’s the worst in order to justify your dislike.

                                                                      1. 2

                                                                        I don’t know if python is especially bad. I personally found npm projects I have tried break when updating dependencies a few years later, and I have not had that experience in Go. Maybe I am just lucky.

                                                                        1. 1

                                                                          It seems to me that the disconnect here is about the scope of what constitutes “breaking changes” in a language. There certainly isn’t an objective definition! Some people consider only the core language and it’s standard library, and others include everything out to its tooling.

                                                                    2. 1

                                                                      Okay, I tried this with a Datasette project from around the same time. (It was actually deployed again in early 2020, so it’s a bit fresher than the Go project, but whatever, close enough.) Again, Node didn’t work. I think the issue with that is that libsass is dead and doesn’t compile anymore, so you need to switch to dart-sass instead. In all likelihood, the fastest solution to the Node issues is to drop all of the dependencies and just start over from scratch with only my user code, since the dependencies were just there to build a Vue project.

                                                                      On the Python side, it wouldn’t work with Python 3.9, but when I used Python 3.7, I got it to run again. Terminal output is below. It only took 15 minutes to get it going, but compare this to Go, which works with the current version of Go even though the package predates modules (which caused a lot of breakage not covered by the Go 1 guarantee) and I got the dependencies upgraded in a total of 5 minutes. By contrast, the Python installations all took long enough that they break flow: since the installation is going to take a while, I switch away from my Terminal, which is chance for me to get distracted and lose my place. I think this project did pretty well because it used your recommended pattern of having a requirements-freeze.txt file and it had a Bash script to automate the actual install commands. But the error when UVLoop was broken was pretty demoralizing: I have no idea how I would fix it, so getting up to Python 3.9 or 3.10 would probably involve a lot more Googling than I’m willing to do for an internet comments example. Again, the simplest fix might be to just blow away what I have now and start from scratch. I think Datasette has been relatively stable in spite of being <1.0, so I suspect that it wouldn’t be that hard to get it working, but again, it’s more than I want to do for an example. A nice thing about Go is that most dependencies don’t use C, so when something does go wrong, like that middleware that was broken in the other project, you aren’t confronted with errors in a language you don’t know using a build system you don’t understand. In general, it’s just much less intimidating to get a Go project back up to speed.

                                                                      So this is fairly reflective of my lived experience: Node projects, especially those that use Webpack, break in ways that are more or less unfixable and need to be restarted from scratch; Python projects can be kept running if you are willing to pin old versions of Python but give a lot of scary compiler errors and don’t have clear paths forward; Go projects can typically be upgraded by typing go get -u ./... and maybe reading some release notes somewhere. Go isn’t perfect and there are still problems, but the quantity of problems is so much less than it creates a qualitative difference in feeling.

                                                                      $ gh repo clone baltimore-sun-data/salaries-datasette
                                                                      Cloning into 'salaries-datasette'...
                                                                      remote: Enumerating objects: 1017, done.
                                                                      remote: Counting objects: 100% (94/94), done.
                                                                      remote: Compressing objects: 100% (72/72), done.
                                                                      remote: Total 1017 (delta 63), reused 23 (delta 20), pack-reused 923
                                                                      Receiving objects: 100% (1017/1017), 53.78 MiB | 4.25 MiB/s, done.
                                                                      Resolving deltas: 100% (568/568), done.
                                                                      Updating files: 100% (74/74), done.
                                                                      (Sat, May 21  12:45:40 PM)
                                                                      $ cd salaries-datasette/
                                                                      (Sat, May 21  12:45:54 PM) (master|✔)
                                                                      $ more README.md
                                                                      # salaries-datasette
                                                                      Public salary data acquired by the Baltimore Sun. Currently, we just have data from the state of Maryland for 2017.
                                                                      
                                                                      ## Usage
                                                                      
                                                                      Run `./run.sh setup` to install locally. The script assumes you have either Python 3 or Homebrew for Mac installed. Run `./run.sh setup-frontend` to install front end dependencies.
                                                                      
                                                                      Run `./run.sh create-db` to create a SQLite database out of the provided CSVs.
                                                                      
                                                                      Run `./run.sh` or `./run.sh serve` to run server at http://localhost:9001.
                                                                      
                                                                      Run the JS/CSS frontend server in another tab with `./run.sh frontend`.
                                                                      
                                                                      `./run.sh format` will format Python and Javascript code according to the coding standards of the project.
                                                                      
                                                                      `Dockerfile` is also provided for running/deploying with Docker. The image can be built with `./run.sh docker-build` and tested with `./run.sh docker`. The server only responds to correct hostnames (not localhost), so edit `/etc/hosts` to add `127.0.0.1   local.salaries.news.baltimoresun.com` and then test http://local.salaries.news.baltimoresun.com in the browser.
                                                                      (Sat, May 21  12:46:06 PM) (master|✔)
                                                                      $ ./run.sh setup
                                                                      
                                                                      snip a ton of output from installing things including a lot of scary errors
                                                                      
                                                                      × Encountered error while trying to install package.
                                                                      ╰─> uvloop
                                                                      
                                                                      note: This is an issue with the package mentioned above, not pip.
                                                                      hint: See above for output from the failure.
                                                                      # status: 1 #
                                                                      (Sat, May 21  12:49:40 PM) (master|✔)
                                                                      $ # by reading the DOCKERFILE, I learn that this used Python 3.7 when it was made
                                                                      (Sat, May 21  12:51:16 PM) (master|✔)
                                                                      $ pyenv install 3.7.13
                                                                      python-build: use openssl@1.1 from homebrew
                                                                      python-build: use readline from homebrew
                                                                      Downloading Python-3.7.13.tar.xz...
                                                                      -> https://www.python.org/ftp/python/3.7.13/Python-3.7.13.tar.xz
                                                                      Installing Python-3.7.13...
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Doc/library/ctypes.rst
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Lib/test/test_unicode.py
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Modules/_ctypes/_ctypes.c
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Modules/_ctypes/callproc.c
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Modules/_ctypes/ctypes.h
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file setup.py
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file 'Misc/NEWS.d/next/Core and Builtins/2020-06-30-04-44-29.bpo-41100.PJwA6F.rst'
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file Modules/_decimal/libmpdec/mpdecimal.h
                                                                      (Stripping trailing CRs from patch.)
                                                                      patching file setup.py
                                                                      python-build: use tcl-tk from homebrew
                                                                      python-build: use readline from homebrew
                                                                      python-build: use zlib from xcode sdk
                                                                      Installed Python-3.7.13 to /Users/adhoc/.pyenv/versions/3.7.13
                                                                      
                                                                      (Sat, May 21  12:55:00 PM) (master|✔)
                                                                      $ ./run.sh setup
                                                                      
                                                                      snip
                                                                      
                                                                      × Encountered error while trying to install package.
                                                                      ╰─> uvloop
                                                                      
                                                                      note: This is an issue with the package mentioned above, not pip.
                                                                      hint: See above for output from the failure.
                                                                      # status: 1 #
                                                                      (Sat, May 21  12:57:08 PM) (master|✔)
                                                                      $ # I become worried that maybe Pyenv didn't activate for some reason, so I try explicitly adding it to my PATH
                                                                      (Sat, May 21  12:59:30 PM) (master|✔)
                                                                      $ PATH=$HOME/.pyenv/versions/3.7.13/bin/:$PATH ./run.sh setup
                                                                      
                                                                      snip
                                                                      
                                                                      success!
                                                                      
                                                                      (Sat, May 21  01:01:58 PM) (master|✔)
                                                                      $ 
                                                                      
                                                        2. 3

                                                          This thread has grown a lot overnight while I was sleeping! I still haven’t caught up, but here is my top of head takeaway:

                                                          I think it’s fair to complain that the Go 1 stability guarantee doesn’t go far enough, but it seems like some people elsewhere in the thread are trying to claim that adding monotonic time somehow breaks the guarantee, which makes no sense to me. At this point, someone citing Fasterthanlime basically means they don’t know anything about Go, IMO because he has been so egregious in his misrepresentation of the language. Just recently, I had to pin a specific subversion of Go 1.18 in my tests because I needed a particular behavior for the Go tool. I don’t consider that to have been the Go team breaking the stability guarantee, just an example of how you can run into the limits of it when you’re talking about the tooling.

                                                          Obviously, it’s going to be impossible to never break anything. (Which is what I take from your points 1 and 2.) If nothing else, security problems can force breaking changes. Certainly, you need to get to a point where you’re happy enough to commit to a design before you stabilize it: Go was not stable at all before version 1. JavaScript wasn’t stable before ECMA etc.

                                                          But the question to me is whether the upstream developers take breaking changes seriously or commit them wantonly. To rephrase your points:

                                                          1. Projects which accept that breaking changes are fact of software development, so they do it whenever it’s convenient.

                                                          2. Projects which accept that breaking changes are fact of software development, so they do it as little as possible.

                                                          I was being a bit too flip when I wrote “You ‘just’ don’t make breaking changes.” That’s like saying, you just don’t write bugs. It is unavoidable sometimes. But there is a qualitative difference as an end developer in relying on a project which attempts to avoid breaking changes and one which does not.

                                                          In Node, I routinely run into software that will not run on the latest versions of Node. When a new version of Node comes out, I don’t think “Oh great, more speed, more features!” I think, “Ugh, crap, what’s going to break this time?” I had a hard to diagnose break in Babel (a very popular library!) that was caused not by a major version jump in Node, but a minor version bump. It was a waste of a day of development time for me for no reason. You wrote “as long as I pay the hosting bill there is no technical reason why it would suddenly stop working.” But in this case, there wasn’t anything I did intentionally which broke my setup. I just hadn’t pinned my version of Node, Homebrew moved up by a minor version because of some other thing, and suddenly I lost a workday. It also broke production because prod was only pinned to the major version not the minor or patch.

                                                          A similar example was that I had an Amazon ECS server using a Docker image to serve some Python app, and one day it just stopped working in prod. The problem was that when the Dockerfile was written, it didn’t specify the version of Python, and then the version where async went from a semi-keyword to a full keyword came out and broke the dependencies I was using. It wouldn’t have mattered if the Docker image had been already baked, but the way this project was setup, the Docker image would be periodically rebuilt from the Dockerfile whenever things would restart or something. That at least was relatively easy to track down and fix because the change of Python versions was noticeable once I started debugging it.

                                                          You call the /v2 thing a “hack” and it is ugly and inelegant, but it does solve this problem: when you make a breaking change, let users upgrade at their own pace, instead of having them accidentally get moved onto the new thing without being aware of it. (In browser JS, "strict mode" and type="module" also have the effect of being opt-in upgrades!) That’s really the core of the so-called “Python problem” to me. Just let me decide when to work through the breaking changes. I’m not expecting eternal support or whatever. I just want something that works today to work tomorrow unless I press the big red “attempt upgrade” button.

                                                          1. 5

                                                            At this point, someone citing Fasterthanlime basically means they don’t know anything about Go, IMO because he has been so egregious in his misrepresentation of the language.

                                                            I’m the one who cited the monotonic time issue. I’m having trouble seeing good faith in this statement, so I’ll bow out of this thread after this. But just so you understand that this is adamantly not the case: I’ve written Go since before 1.0, contributing to some of the largest projects in the ecosystem, and as a manager moved several teams over to using it (from Python, no less.) I also don’t think those credentials should be necessary for a critique.

                                                            I had a hard to diagnose break in Babel (a very popular library!) that was caused not by a major version jump in Node, but a minor version bump.

                                                            To reiterate, this has happened to me with minor version bumps in Go, due to both modules and stdlib changes. This is even worse because it was Go itself, not a third-party library.

                                                            You call the /v2 thing a “hack” and it is ugly and inelegant, but it does solve this problem: when you make a breaking change, let users upgrade at their own pace

                                                            This actually touches on a major reason why Go’s ecosystem could be so unstable before modules: you could either vendor which had its own can of worms, or rely on authors using this hack. Both patterns emerged as common practice only after years of Go devs experiencing breaking changes in libraries. You could argue that those instabilities don’t apply to Go itself, which I suppose is fair, but that applies to your argument about Babel as well.

                                                        3. 13

                                                          Go makes breaking changes all of the time. The last one that bit me was when modules were enabled by default. Suddenly packages starting behaving differently depending on a variety of factors, including the version number of the package: https://stackoverflow.com/questions/57355929/what-does-incompatible-in-go-mod-mean-will-it-cause-harm/57372286#57372286

                                                          Python at least had the sense to bundle up all the breakages in a major version change, which was released 15 years ago.

                                                          1. 8

                                                            Eh no. Python does not follow semantic versioning and makes intentionally breaking changes between minor versions. In fact Python 3.x releases come with documentation titled “Porting to Python 3.x” which lists all breaking changes made intentionally.

                                                            1. 6

                                                              Python makes breaking stdlib changes in minor version releases. Not even remotely the same as a tooling change.

                                                              1. 3

                                                                I’ve never been affected by stdlib changes in python in a minor release. I have by go, where it suddenly stopped respecting system DNS settings. Or there were the backwards-incompatible changes to time, maybe best summarized here.

                                                                1. 4

                                                                  I believe you, but you are lucky. With search I found things like https://github.com/wazuh/wazuh/issues/13365 which matches my experience.

                                                                  1. 3

                                                                    I know this isn’t likely to change anyone’s mind, but the thing you linked is an example of something that had been deprecated and raising deprecation warnings for years. Here’s an example warning I get from a Python 3.7 install I had lying around (oldest I could find, I tend not to keep EOL’d Pythons on my personal laptop):

                                                                    DeprecationWarning: Using or importing the ABCs from ‘collections’ instead of from ‘collections.abc’ is deprecated since Python 3.3,and in 3.9 it will stop working

                                                                    And it appears they actually held off and didn’t finally remove that until 3.10. That’s at least four years after Python 3.7 (which issued that warning). It’s nearly ten years after Python 3.3.

                                                                    Python does use a rolling deprecation cycle, yes. So do some major Python projects like Django. This means you should ensure you’re bubbling up deprecation warnings in your CI, and probably read release notes when new versions come out, yes.

                                                                    But these things don’t just come surprise out of nowhere; they’re documented, they raise warnings, they’re incorporated into the release cycles. Knowing how Python’s deprecation cycles work is, for a Python user, the same kind of table stakes as knowing how semantic versioning works is for a Rust/cargo/crates user – if you updated a crate across a major version bump and it broke your code, everyone would tell you that you could have seen that coming.

                                                                  2. 2

                                                                    It happens, no doubt, but IME Python’s changes are much more egregious than Go’s few changes over the years. Where Go does make changes, they are typically as solutions to bugs, not gratuitous API changes.

                                                                    Also, speaking personally, I try to be as objective as possible and fasterthanli.me is not an objective source in any sense. It’s clickbait. There’s no pretence of objectivity.

                                                                    1. 13

                                                                      I’d like to point out that this thread has gone from a claim that Go has maintained backwards compatibility to, now, a claim that Go’s backwards-incompatible changes just aren’t as “egregious” as Python’s, and to what’s basically an ad hominem attack on someone who criticized Go.

                                                                      Which is kind of a microcosm of this whole framing of “Python problem” or “Node problem”. What it’s really about is not some magical language and ecosystem that never has backwards-incompatible changes, what it’s about is subjective taste. You think Go’s breaking changes are not as “egregious” and are “solutions to bugs” while Python’s are “gratuitous”. But that’s a subjective judgment based on your tastes and opinions. Someone else can have an opposite and equally-valid subjective opinion.

                                                                      Or, more bluntly: “No breaking changes” nearly always turns out to actually mean “Breaking changes, but only ones I personally think are justified/tolerable, and I don’t think yours are”. Which is where this thread predictably went within the space of just a few replies.

                                                                      Getting back to my original claim: change is inevitable. Entities which produce software can adapt to it and make it a normal and expected part of their processes, or they can suffer the consequences of not doing so. There is no third option for “all external change stops”. Nothing that lives does so changelessly.

                                                                      1. 3

                                                                        Or, more bluntly: “No breaking changes” nearly always turns out to actually mean “Breaking changes, but only ones I personally think are justified/tolerable, and I don’t think yours are”. Which is where this thread predictably went within the space of just a few replies.

                                                                        No I don’t think so. It has nothing to do with opinion and everything to do with experience. What someone sees directly is how they perceive reality. I’m expressing my perception of reality as someone who has experience of both Python and Go, and m0th is expressing their experience.

                                                                        I’m not minimising m0th’s view, which is why I phrased it as “in my experience”.

                                                                        Getting back to my original claim: change is inevitable. Entities which produce software can adapt to it and make it a normal and expected part of their processes, or they can suffer the consequences of not doing so. There is no third option for “all external change stops”. Nothing that lives does so changelessly.

                                                                        Change is inevitable, I agree, but I do think the degree matters. Python makes breaking changes often, removing APIs, etc. Go does not and only with very good reason.

                                                                        1. 3

                                                                          Change is inevitable, I agree, but I do think the degree matters. Python makes breaking changes often, removing APIs, etc. Go does not and only with very good reason.

                                                                          Again, the original claim at the start was that there are languages which don’t have breaking changes, and Go was specifically named as an example. That has now been walked back to the kinds of statements you are making. And your statements are, effectively, just that in your opinion one language’s (Go) breaking changes are justified and not too frequent, while another language’s (Python) breaking changes are not justified and too frequent. Which is just you stating your own personal tastes and opinions. And it’s fine as long as you are willing to admit that. It is not so fine to present one’s personal tastes and opinions as if they are objective facts. It also is not so fine to engage in the kind of ad hominem you did about criticism of Go.

                                                                          1. 3

                                                                            Again, the original claim at the start was that there are languages which don’t have breaking changes, and Go was specifically named as an example.

                                                                            I didn’t make that claim, so I’m not sure why you’re arguing with me about it.

                                                                            Which is just you stating your own personal tastes and opinions. And it’s fine as long as you are willing to admit that.

                                                                            I did? I explicitly said “In My Experience”. I’m not sure how I can be any clearer.

                                                                            It is not so fine to present one’s personal tastes and opinions as if they are objective facts. It also is not so fine to engage in the kind of ad hominem you did about criticism of Go.

                                                                            What are you even talking about? I legitimately can’t even understand what you’re referring to. Where’s the “ad hominem” comment I made? I think the most controversial thing I said was

                                                                            “Python makes breaking stdlib changes in minor version releases.”

                                                                            Which is objectively true as mentioned by other commenters. I made no judgement about whether it was justified or not. It’s also not “ad hominem”, which would require Python to have a position on this.

                                                                            Anyway, I think you’re taking this way too personally for some reason. I like Python, I have used it for many years. But I’m out.

                                                                            1. 3

                                                                              Where’s the “ad hominem” comment I made?

                                                                              IIUC, ubernostrum is referring to you explaining that fasterthanli.me is not a reliable source of information. That’s not an ad hominem though. His attacks are so scattershot that if someone cites them, it’s totally fair to just handwave it away.

                                                                              1. 3

                                                                                Where’s the “ad hominem” comment I made?

                                                                                It’s this:

                                                                                Also, speaking personally, I try to be as objective as possible and fasterthanli.me is not an objective source in any sense. It’s clickbait. There’s no pretence of objectivity.

                                                                                You don’t bother to engage with the content, just brush off the author with a quick smear and then move on. Which is a problem, because the content is reasonably well-argued, from my perspective as someone who has a bit of Go experience and initially couldn’t quite describe why it rubbed me the wrong way. Putting into words the way that Go (which is not unique in this, but is a prominent example of it) likes to pretend complex things are simple, rather than just admitting they’re complex and dealing with it, was extremely useful for me, both for giving me a way to talk about what bugged me in Go and because it relates to things I’ve ranted about in the Python world previously (most notably why Python 3’s string changes were the right thing to do).

                                                                              2. 2

                                                                                Go the language doesn’t have breaking changes, in the sense that code written against a 1.0 language spec will — generally— continue to compile and run the same way against any 1.x language spec compiler. This isn’t an absolute statement of fact, but it’s a design principle that’s taken very seriously and is violated very rarely. The tooling doesn’t necessarily abide the same rules.

                                                                                1. 1

                                                                                  Your comment is a bit of a roller coaster.

                                                                                  • Starts with “doesn’t have breaking changes”
                                                                                  • Immediately qualifies with “in the sense that…”
                                                                                  • Then walks it back with “This isn’t an absolute statement of fact”
                                                                                  • Then walks it back even further with “is violated very rarely”
                                                                                  • Then throws it all out the window with “The tooling doesn’t necessarily abide the same rules”

                                                                                  I’m not even sure what that’s trying to say.

                                                                  3. 9

                                                                    Go 1 has been stable for 10 years now.

                                                                    If you just ignore all those breaking changes they made..

                                                                    1. 1

                                                                      I only remember Modules. After Modules landed I never experienced any breaking build when updating to a new Go version. A whole different story was updating Java versions and the dozens of subtle ways they can break your service, especially at run-time (caused by some Spring DI magic).

                                                                      1. 1

                                                                        What breaking language changes have been made?

                                                                        1. 3

                                                                          Modules seems like the biggest change.

                                                                          1. 3

                                                                            I mean, Go module is not part of Go 1 stability guarantee. In my opinion, this shows how limited Go’s stability guarantee is. Go 1 is stable, but Go is not, at least if you are using “go build” to build your Go code.

                                                                            1. 2

                                                                              I agree but that’s not a language change, and the impact is not as significant as random language changes. I can still use and build a package from 8 years ago with no issue. And whatever tool they happened to use to manage dependencies 8 years ago will still work fine (probably).

                                                                              1. 3

                                                                                I saw some breaking changes in one of our old projects. Written in the Go v1.4 era, IIRC. I checked it with a Go v1.14 release, and boom, it doesn’t compile due to the module changes.

                                                                                Yes, it wasn’t that hard to fix (it only took a few minutes of Internet searching), but I still count that as a breaking change.

                                                                    2. 2

                                                                      When was there ever a breaking change in a new version of ecmascript? Node is not a language.

                                                                      1. 4

                                                                        There’s a bunch of things that vary in stability.

                                                                        • V8 the interpreter breaks working JS code very seldom
                                                                        • The libraries that come with Node break JS code a little more often, but still IME not very often.
                                                                        • V8 breaks native extensions very often. The NodeJS ecosystem discourages writing them because of this.
                                                                        • Some add-on packages from npm break their consumers all the time.

                                                                        Many packages are extremely careful not to break consumers. Others are less so. The experience you have with backwards compatibility tends to track the backwards compatibility stance of the worst thing in your entire dependency tree. When you have tens of thousands of transitive dependencies, you usually end up seeing 99.99%-ile bad behaviour somewhere in there at least once.

                                                                        1. 1

                                                                          The core problem is that a handful of “core” packages break, and nodes ecosystem is way too much about plugins, so many things that you use have 3 layers to them (all maintained by different people)

                                                                          The ecosystem would be a lot more stable if we were vendoring in packages more

                                                                        2. 2

                                                                          Node is a development target. The pure abstract notion of a “language” doesn’t really matter here, because people write code for Node specifically.

                                                                          And Node does make breaking changes. It literally makes semver-major releases, with backwards-incompatible changes that can break existing npm packages (mainly due to changes in the native API, but there also have been changes to Node’s standard library).

                                                                          For example, I can’t build any projects that used Gulp v3. Node broke packages that it depends on, and I either have to run deprecated/unsupported/outdated version of Node, or rewrite my build scripts. OTOH a Rust/Cargo project I’ve developed at the same time still works with the latest version of Rust/Cargo released yesterday.

                                                                          1. 2

                                                                            Yes, that’s why I said “Node ecosystem” which breaks all the damn time and not “browser ECMAScript” which has not broken since standardization.

                                                                            1. 2

                                                                              The quote you posted says language, not ecosystem. Your comparison was a false equivalency.

                                                                            2. 1

                                                                              ecmascript itself is a language but not a language implementation, so while you can write a lot of code in ecmascript, at the end of the day the ecmascript specification can’t run it, so you’ll need to run it using an implementation, that’s why people are talking about the Node ecosystem, the language didn’t break the ecosystem did

                                                                          1. 10

                                                                            Them: “Leslie Lamport may not be a household name,[…]”

                                                                            Me: “The hell he isn’t.” [rage close]

                                                                            (I opened it back up and read it anyway. It was actually really interesting. But my rage close was real.)

                                                                            1. 17

                                                                              There are whole households out there that don’t have a single graduate degree in them. Amazing, I know!

                                                                              That said, I didn’t actually know LL was the one behind TLA+, so it was a useful read for me too. (Also, it turns out he actually does look somewhat like the fluffy lion on the cover of the LaTeX book!)

                                                                              1. 3

                                                                                This is a hypertext book that I intended to be the way to learn TLA+ and PlusCal, until I realized that people don’t read anymore and I made the video course.

                                                                                1. 3

                                                                                  Yeah, I knew he did Lamport clocks but didn’t know he was also the guy who did LaTeX and TLA.

                                                                                  1. 4

                                                                                    Inverse for me, I never made the connection between LaTeX Lamport and clock Lamport.

                                                                                    1. 4

                                                                                      One did happen before the other.

                                                                                      1. 10

                                                                                        Can we really be sure about that.

                                                                                  2. 3

                                                                                    I only learned about his writing LaTeX after reading his TLA+ book. Dude doesn’t have much ego, and he only made his name better known when he started actively advocating for formal methods.

                                                                                  3. 4

                                                                                    I saw that and ran a Twitter poll

                                                                                    without googling, can you name one thing Leslie Lamport is known for?

                                                                                    • yes: 70.1%
                                                                                    • no: 29.9%

                                                                                    Not as good as I’d like, but not as bad as the article makes it sound. Granted, this is a heavily skewed demographic. I ran the same poll at work and got 0% yes.

                                                                                    1. 3

                                                                                      And even then, people tend to know him more for LaTeX than for his much more important work on distributed computing. Which I’ve heard bothered him.

                                                                                      1. 5

                                                                                        I imagine that there are more people writing professional documents than working on distributed computers.

                                                                                        1. 1

                                                                                          On the other hand, I imagine that there are more people using distributed computers than people writing documents. Probably.

                                                                                        2. 5

                                                                                          I can kind of see why that bothered him. Many people viewed TeX as the real, manly typesetting system, and LaTeX was for weaklings. Lamport received the impression of a hippie simplifying Knuth - more an enthusiastic college lecturer than a “real” computer scientist.

                                                                                          OTOH LaTeX made TeX usable, and facilitated the distribution of a lot of science. That has to count for something.

                                                                                        3. 2

                                                                                          I know him for Lamport clocks and not much else :)

                                                                                          1. 1

                                                                                            Heheh. I saw the Twitter poll and thought of this story. I follow you on Twitter now.

                                                                                        1. 9

                                                                                          Not sure how to feel about that. Those new styles certainly look cleaner but I reflexively dislike introducing new ways to do the same thing. (Though I do think try was ok.)

                                                                                          Edit: On second thought, the arrow style looks really weird. I think if an anonymous struct has to have the word struct, then an anonymous function should have the word func.

                                                                                          1. 3

                                                                                            On second thought, the arrow style looks really weird. I think if an anonymous struct has to have the word struct, then an anonymous function should have the word func.

                                                                                            I’m used to the fat arrow from JavaScript. In the abstract, I agree that it would be better to reuse the func keyword, but given that to make it work grammatically, they would have to drop the parentheses, which makes things look misgrouped, I think all things equal, the fat arrow is the lesser of two evil.

                                                                                          1. 35

                                                                                            As I was reading this wonderful writeup, I had a nagging feeling that most certainly ‘someone on the internet’ will bring up some half-assed moralizing down to bear on the author. And sure enough, it’ the first comment on lobsters.

                                                                                            I think it’s a beautiful and inspiring project, making one think about the passage of time and how natural processes are constantly acting on human works.

                                                                                            @mariusor, I recommend you go troll some bonsai artists, they too are nothing but assholes who carve hearts in trees.

                                                                                            1. 8

                                                                                              We do have an ethical obligation to consider how our presence distorts nature. Many folks bend trees for many purposes. I reuse fallen wood. But we should at least consider the effects we have on nature, if for no other reason than that we treat nature like we treat ourselves.

                                                                                              I could analogize bonsai to foot-binding, for example. And I say that as somebody who considered practicing bonsai.

                                                                                              1. 11

                                                                                                Foot binding is a social act in which women are deliberately crippled in exchange for access to certain social arrangements in which they don’t need to be able to walk well. The whole practice collapsed once the social arrangement went away. It’s very different than just getting a cool gauge piercing or whatever.

                                                                                                1. 6

                                                                                                  Thank you Corbin for addressing the substance of my admittedly hot-headed comment. It did give me food for thought.

                                                                                                  I am definitely in agreement with you on the need to consider the impact of our actions on the environment. I have a bunch of 80-year old apple trees in my yard which were definitely derailed, by human hands, from their natural growth trajectory. This was done in the interest of horticulture, and I still benefit from the actions of the now-deceased original gardener. All in all I think the outcome is positive, and perhaps will even benefit others in the future if my particular heritage variety of apple gets preserved and replicated in other gardens. In terms of environmental impact, I’d say it’s better for each backyard to have a “disfigured” but fruitful apple tree than to not have one, and rely on industrial agriculture for nutrition.

                                                                                                  Regarding the analogy with foot-binding, which I think does hold to a large extent (i.e it involves frustrating the built-in development pattern of another, without the other’s consent) – the key difference is of course the species of the object of the operation.

                                                                                                  1. 7

                                                                                                    Scale matters too, I think.

                                                                                                    I’m a gardener who grows vegetables, and I grow almost everything from seed - it’s fun and cheap. That means many successive rounds of culling: I germinate seeds, discard the weakest and move the strongest to nursery pots, step out the strongest starts to acclimatize to the weather, plant the healthiest, and eventually thin the garden to only the strongest possible plants. I may start the planting season with two or three dozen seeds and end up with two plants in the ground. Then throughout the year, I harvest and save seeds for next, often repeating the same selecting/culling process.

                                                                                                    Am I distorting nature? Absolutely, hundreds of times a year - thousands, perhaps, if I consider how many plants I put in the ground. But is my distortion significant? I don’t think so; I don’t think that, even under Kant’s categorical imperative, every back-yard gardener in the universe selecting for their own best plants is a problem. It fed the world, after all!

                                                                                                    1. 3

                                                                                                      My friend who is a botanist told me about research he did into how naïve selection produces worse results. Assume you have a plot with many variants of wheat, and at the end of the season, you select the best in the bunch for next year. If you’re not careful, the ones you select are the biggest hoarders of nutrients. If you had a plot with all that genotype, it would do poorly, because they’re all just expertly hoarding nutrients away from each other. The ones you want are the ones that are best at growing themselves while still sharing nutrients with their fellow plants. It’s an interesting theory and he’s done some experiment work to show that it applies in the real world too.

                                                                                                      1. 2

                                                                                                        The ones you want are the ones that are best at growing themselves while still sharing nutrients with their fellow plants.

                                                                                                        So maybe you’d also want to select some of the ones next to the biggest plant to grow in their own trials as well.

                                                                                                2. 3

                                                                                                  I think it’s a beautiful and inspiring project, making one think about the passage of time and how natural processes are constantly acting on human works.

                                                                                                  I mean… on the one hand, yes, but then on the other hand… what, we ran out of ways to make one think about the passage of time and how natural processes are constantly acting on human works without carving into things, so it was kind of inevitable? What’s wrong with just planting a tree in a parking lot and snapping photos of that? It captures the same thing, minus the tree damage and leaving an extra human mark on a previously undisturbed place in the middle of the forest.

                                                                                                  1. 14

                                                                                                    As I alluded in my comment above, we carve up and twist apple trees so that the actually give us apples. If you just let them go wild you won’t get any apples. Where do you get your apples from? Are you going to lecture a gardener who does things like grafting, culling, etc., to every tree she owns?

                                                                                                    The same applies here: the artist applied his knowledge of tree biology and his knowledge of typography to get a font made by a tree. I think that’s pretty damn cool. I am very impressed! You can download a TTF! how cool is that?

                                                                                                    Also, it’s not ‘in the middle of a forest’, but on his parents’ property, and the beech trees were planted by his parents. It’s his family’s garden and he’s using it to create art. I don’t get the condemnation, I think people are really misapplying their moral instincts here.

                                                                                                    1. 4

                                                                                                      Are you going to lecture a gardener who does things like grafting, culling, etc., to every tree she owns?

                                                                                                      No, only the gardeners who do things like grafting, culling etc. just to write a meditative blog post about the meaning of time, without otherwise producing a single apple :-). I stand corrected on the forest matter, but I still think carving up trees just for the cool factor isn’t nice. I also like, and eat, beef, and I am morally conflicted about it. But I’m not at all morally conflicted about carving up a living cow just for the cool factor, as in, I also think it’s not nice. Whether I eat fruit (or beef) has no bearing on whether stabbing trees (or cows) for fun is okay.

                                                                                                      As for where I get my apples & co.: yes, I’m aware that we carve up and twist apple trees to give us apples. That being said, if we want to be pedantic about it, back when I was a kid, I had apples, a bunch of different types of prunes, sour cherries, pears and quince from my grandparents’ garden, so yeah, I know where they come from. They pretty much let the trees go wild. “You won’t get any apples” is very much a stretch. They will happily make apples – probably not enough to run a fruit selling business off of them, but certainly enough for a family of six to have apples – and, as I very painfully recall, you don’t even need to pick them if you’re lazy, they fall down on their own. The pear tree is still up, in fact, and at least in the last 35 years it’s never been touched in any way short of picking the pears on the lowest two or three branches. It still makes enough pears for me to make pear brandy out of them every summer.

                                                                                                      1. 6

                                                                                                        I concede your point about the various approaches as to what is necessary and unnecessary tree “care” :)

                                                                                                        No, only the gardeners who do things like grafting, culling etc. just to write a meditative blog post about the meaning of time, without otherwise producing a single apple :-).

                                                                                                        But my argument is that there was an apple produced, by all means. You can enjoy it here: https://bjoernkarmann.dk/occlusion_grotesque/OcclusionGrotesque.zip

                                                                                                  2. 3

                                                                                                    Eh. I hear what you’re saying, but you can’t ignore the fact that “carving letters into trees” has an extremely strong cultural connection to “idiot disrespectful teenagers”.

                                                                                                    I can overlook that and appreciate the art. I do think it’s a neat result. But then I read this:

                                                                                                    The project challenges how we humans are terraforming and controlling nature to their own desires, which has become problematic to an almost un-reversible state. Here the roles have been flipped, as nature is given agency to lead the process, and the designer is invited to let go of control and have nature take over.

                                                                                                    Nature is given agency, here? Pull the other one.

                                                                                                    1. 3

                                                                                                      You see beautiful and wonderful writeup, I see an asshole with an inflated sense of self. I think it’s fair that we each hold to our own opinions and be at peace with that. Disrespecting me because I voiced it is not something I like though.

                                                                                                      1. 15

                                                                                                        I apologize at venting my frustration at you in particular.

                                                                                                        This is a public forum though, and just as you voiced your opinion in public, so did I. Our opinions differ, but repeatedly labeling other as “assholes” (you did in in your original post and in the one above) sets up a heated tone for the entire conversation. I took the flame bait, you might say.

                                                                                                        Regarding ‘inflated sense of self’ – my experience with artists in general (I’ve lived with artists) is that it’s somewhat of a common psychological theme with them, and we’re better off judging the art, not the artist.

                                                                                                    1. 1

                                                                                                      It’s weird that the first thing you criticize in a Critical Retrospective is something syntax-related that you yourself call superficial. It makes it hard to take the rest of the post seriously

                                                                                                      1. 29

                                                                                                        If syntax impacts understandability, is it actually superficial?

                                                                                                        1. 19

                                                                                                          Because I don’t think that’s the fault of the syntax. Huge part of criticism is expectations/preferences and lack of understanding of the trade-offs that made it the way it is. When Rust is different than whatever other language someone is used to, they compare familiar with unfamiliar (see Stroustrup’s Rule). But it’s like saying the Korean alphabet is unreadable, because you can’t read any of it.

                                                                                                          People who don’t like Rust’s syntax usually can’t propose anything better than a bikeshed-level tweak that has other downsides that someone else would equally strongly dislike.

                                                                                                          For example, <> for generics is an eyesore. But if Rust used [] for generics, it’d make array syntax either ambiguous (objectively a big problem) or seem pointlessly weird to anyone used to C-family languages. Whatever else you pick is either ambiguous, clashes with meaning in other languages, or isn’t available in all keyboard layouts.

                                                                                                          The closure syntax || expr may seem like line noise, but in practice it’s important for closures to be easy to write and make it easy to focus on their body. JS went from function { return expr } to () => expr. Double arrow closures aren’t objectively better, and JS users criticize them too. A real serious failure of Rust regarding closures is that they have lifetime elision rules surprisingly different than standalone functions, and that is a problem deeper than the syntax.

                                                                                                          Rust initially didn’t have the ? shortcut for if err != nil { return nil, err } pattern, and it had a problem of a low signal-to-noise ratio. Rust then tried removing boilerplate with a try!() macro, but it worked poorly with chains of fallible function calls (you’d have a line starting with try!(try!(try!(… and then have to figure out where each of them have the other paren). Syntax has lots of trade-offs, and even if the current one isn’t ideal in all aspects, it doesn’t mean alternatives would be better.

                                                                                                          And there are lots of things that Rust got right about the syntax. if doesn’t have a “goto fail” problem. Function definitions are greppable. Syntax of nested types is easy to follow, especially compared to C’s “spiral rule” types.

                                                                                                          1. 14

                                                                                                            I think a lot of criticism about syntax is oblique. People complain about “syntax” because it’s just… the most convenient way to express “I find it hard to learn how to write correct programs, and I find it hard to interpret written programs, even after substantial practice”.

                                                                                                            Lots of people complain that Common Lisp syntax is hard. Lisp syntax is so easy that you can write a parser in a few dozen lines. Common Lisp has a few extra things but, realistically, the syntax is absolutely trivial. But reading programs written in it is not, even after substantial practice, and I get that (as in, I like Common Lisp, and I have the practice, and I get that).

                                                                                                            Same thing here. A lot of thought went into Rust’s syntax, probably more than in, say, C’s syntax, if only because there was a lot more prior art for Rust to consider. So there’s probably not much that can be done to improve Rust’s syntax while not basically inventing another language. That doesn’t take away from the fact that the language is huge, so it has a syntax that’s unambiguous and efficient but also huge, so it’s just a whole lot of it to learn and keep in your head at once. I get it, I’ve been writing Rust on and off but pretty much weekly for more than an year now and I still regularly need to go back to the book when reading existing code. Hell, I still need it when reading existing code that I wrote. You pay a cognitive price for that.

                                                                                                            1. 3

                                                                                                              “I find it hard to learn how to write correct programs . . .

                                                                                                              Do you believe “correctness” is a boolean property of a program?

                                                                                                              1. 1

                                                                                                                I do, as in, I think you can always procure a “correctness oracle” that will tell you if a program’s output is the correct one and which, given a log of the program’s operations, can even tell you if the method through which it achieved the result is the correct one (so it can distinguish between correct code and buggy code that happens to produce correct output). That oracle can be the person writing the program or, in commercial settings, a product manager or even a collective – a focus group, for example. However:

                                                                                                                • That oracle works by decree. Not everyone may agree with its edicts, especially with user-facing software. IMHO that’s inherent to producing things according to man-made specs. There’s always an “objective” test to the correctness of physics simulation programs, for example, but the correctness of a billing program is obviously tied to whatever the person in charge of billings thinks is correct.
                                                                                                                • The oracle’s answer may not be immediately comprehensible, and they are not necessarily repeatable (like the Oracle in Delphi, it’s probably best to consider the fact that its answers do come from someone who’s high as a kite). IMHO that’s because not all the factors that determine a program’s correctness are inherent to the program’s source code, and presumably, some of them may even escape our quantitative grasp (e.g. “that warm fuzzy feeling” in games). Consequently, not all the knowledge that determines if a program is correct may reside with the programmer at the time of writing the code.

                                                                                                                More to the point, I think it’s always possible to say if something is a bug or a feature, yes :-D.

                                                                                                                1. 1

                                                                                                                  Wow! I guess I can just say that I wish I worked in your domain! 😉 I can’t think of more than a handful of programs I’ve written in my entire life which have a well-defined notion of correct, even in part. Almost all of my programs have been approximate models of under-specified concepts that can change at the whims of their stakeholders. Or, as you say it,

                                                                                                                  the correctness of a billing program is obviously tied to whatever the person in charge of billings thinks is correct.

                                                                                                                  Exactly!

                                                                                                                  not all the knowledge that determines if a program is correct may reside with the programmer at the time of writing the code.

                                                                                                                  In my experience it rarely exists anywhere! Not in one person, or many, or even conceptually.

                                                                                                                  1. 1

                                                                                                                    I can’t think of more than a handful of programs I’ve written in my entire life which have a well-defined notion of correct, even in part.

                                                                                                                    Oh, don’t get me wrong – that describes most of the code I wrote, too, even some of the code for embedded systems :-D. It may well be the case that, for many programs, the “correct” way to do it currently escapes everyone (heh, web browsers, for example…) But I am content with a more restricted definition of correctness that embraces all this arbitrariness.

                                                                                                              2. 2

                                                                                                                Well, there was a lot of prior art even when C was created, and they actively chose to disregard it. They also chose to disregard discoveries in C itself in the 70s and 80s, freezing the language far too early considering the impact it would have in the following decades.

                                                                                                              3. 4

                                                                                                                it’s like saying the Korean alphabet is unreadable, because you can’t read any of it.

                                                                                                                But like there is a reasonably objective language difficulty ranking index (from the perspective of English-native speakers) and Korean is squarely in the most-difficult tranche, I guess in no small part due to its complex symbology, at least in comparison to Roman alphabets. Are you saying that this dimension of complexity is, net, irrelevant?

                                                                                                                1. 11

                                                                                                                  Korean uses the Hangul alphabet, which is very easy to learn. It’s much simpler than our alphabet. You can learn Hangul in a day or two. You’re thinking of Japanese, which is a nightmare based on people writing Chinese characters in cursive and italics while drinking a bottle of sake.

                                                                                                                  1. 1

                                                                                                                    some simplified hanzi does look like kanji, but I would appreciate an example of a japanese character looking like a cursive or italic version of a chinese glyph before I go on to tell your analogy to everyone at parties.

                                                                                                                    1. 1

                                                                                                                      It’s not an analogy. It’s the historical truth of kana: https://en.wikipedia.org/wiki/Kana. Japanese kanji and hanzi are mostly the same modulo some font changes and simplification in the 20th c.

                                                                                                                      1. 1

                                                                                                                        I meant the drunken japanese people part.

                                                                                                                        1. 3

                                                                                                                          We can’t prove they weren’t drunk. :-)

                                                                                                                  2. 11

                                                                                                                    from the perspective of English-native speakers

                                                                                                                    I think that’s what they were getting at; there’s nothing inherently difficult about it but your background as an English speaker makes it look hard to read when objectively speaking it’s dramatically simpler than English due to its regularity and internal logic.

                                                                                                                    1. 2

                                                                                                                      I guess I would say that there is no “objectively speaking” in this domain? Like, there is no superhuman who can look at things invariant of a language background.

                                                                                                                      1. 3

                                                                                                                        If you’re talking about “easy to learn” then I agree.

                                                                                                                        If you’re talking about simplicity, then I disagree. The number of rules, consistency, and prevalence of exceptions can be measured without reference to your background.

                                                                                                                    2. 7

                                                                                                                      I’ve specifically mentioned the Hangul alphabet (a syllabary, strictly speaking), not the language. The Korean language (vocabulary, grammar, spoken communication) may be hard to learn, but the alphabet itself is actually very simple and logical. It’s modern, and it has been specifically designed to be easy to learn and a good fit for the Korean language, rather than being a millennia-old historical borrowed mash-up like many other writing systems.

                                                                                                                      I think it’s a very fitting analogy to having an excellent simple syntax for a complex programming language. You may not understand the syntax/alphabet at all, but it doesn’t mean it’s bad. And the syntax/alphabet may be great, but the language it expresses may still be difficult to learn for other reasons.

                                                                                                                      With Rust I think people complaining about the syntax are shooting the messenger. For example, T: for<'a> Fn(&'a) makes lifetime subtyping contravariant for the loan in the argument of a function item trait in a generic trait bound. Is it really hard because of the syntax? No. Even when it’s expressed in plain English (with no computer language syntax at all) it’s an unintelligible techno-babble you wouldn’t know how to use unless you understand several language features it touches. That for<'a> syntax is obscure even by Rust’s standards, but syntactically it’s not hard. What’s hard is knowing when it needs to be used.

                                                                                                                    3. 4

                                                                                                                      People who don’t like Rust’s syntax usually can’t propose anything better than a bikeshed-level tweak that has other downsides that someone else would equally strongly dislike.

                                                                                                                      The problem with Rust’s syntax isn’t that they made this or that wrong choice for expressing certain features; it’s that there’s simply far too much of it. “Too many notes,” as Joseph II supposedly said.

                                                                                                                      1. 3

                                                                                                                        I agree with this, which is why I object to blaming the syntax for it. For a language that needs to express so many features, Rust’s syntax is doing well.

                                                                                                                        Rust chose to be a language that aims to have strong compile-time safety, low-level control, and nearly zero run-time overhead, while still having higher-level abstractions. Rust could drop a ton of features if it offered less control and/or moved checks to run-time or relaxed safety guarantees, but there are already plenty of languages that do that. Novelty of Rust is in not compromising in any of these, and this came at a cost of having lots of features to control all of these aspects.

                                                                                                                        1. 4

                                                                                                                          You can have many features without a lot of syntax. See Lisp.

                                                                                                                          1. 2

                                                                                                                            If you pick the feature set for simplicity. Rust had other goals.

                                                                                                                            1. 4

                                                                                                                              I literally just said that simple syntax doesn’t necessitate simple features.

                                                                                                                            2. 2

                                                                                                                              I think Lisp gets away here only on a technicality. It can still have plenty of obscure constructs to remember, like the CL’s (loop).

                                                                                                                              The example from the article isn’t really any simpler or more readable if you lispify it:

                                                                                                                              (try (map-result (static-call (def-lifetime a-heavy (:Trying :to-read a-heavy)) 
                                                                                                                                  syntax (lambda (like) (can_be this maddening))) ()))
                                                                                                                              

                                                                                                                              It could be made nicer if it was formatted in multiple lines, but so would the Rust example.

                                                                                                                            3. 1

                                                                                                                              I don’t know. I strongly suspect that in the coming years, we will see new languages that offer the same safety guarantees as Rust, also with no runtime, but with syntax that is simpler than Rust. Lately I’ve seen both Vale and Koko exploring this space.

                                                                                                                        2. 12

                                                                                                                          The syntax complexity of Rust is actually a big factor in why I abandoned my effort to learn it. I was only learning on my own time, and came to the realization I had a long way to go before I’d be able to pick apart a line like the author’s example.

                                                                                                                          So for me, it wasn’t just superficial.

                                                                                                                          1. 5

                                                                                                                            The syntax complexity of Rust is actually a big factor in why I abandoned my effort to learn it.

                                                                                                                            Same.

                                                                                                                          2. 3

                                                                                                                            If syntax impacts understandability, is it actually superficial?

                                                                                                                            I’d say so.

                                                                                                                            The problem is that “this syntax is ugly” is a completely subjective judgement largely influenced by the peculiarities of ones’ own background. Coming from Perl and Ruby, I happen to find Rust pleasant to look at and easy to read, whereas I find both Python and Go (which many other people prefer) unreasonably frustrating to read and just generally odd-looking. It’s not that Python and Go are doing anything objectively less understandable, per-se, but they’re certainly have an unfamiliar look, and people react to unfamiliarity as if it were objectively incorrect rather than just, well, making unfamiliar choices with unfamiliar tradeoffs.

                                                                                                                            It’s pure personal preference, and framing ones’ personal preferences as something that has objective reality outside oneself and which some other party is doing “wrong” is, to me, the definition of a superficial complaint.

                                                                                                                            1. 8

                                                                                                                              It’s pure personal preference

                                                                                                                              Is it pure personal preference? I dunno. Personal preference is a part of it, but I don’t think it’s controversial to say that Python is in general easier to understand than the q language, for example. Human cognition and coherence actually abides pretty well-defined rules, at the macro scale. Sigils are harder to grok than words. And so on.

                                                                                                                              1. 12

                                                                                                                                Personal preference is a part of it, but I don’t think it’s controversial to say that Python is in general easier to understand than the q language, for example.

                                                                                                                                Maybe, maybe not. What I do think is that if we’re going to try to make objective claims, we need some real objective measures and measurements. These conversations tend to be nothing but pseudoscience-y assertions and anecdata masquerading as irrefutable facts.

                                                                                                                                Human cognition and coherence actually abides pretty well-defined rules, at the macro scale. Sigils are harder to grok than words.

                                                                                                                                (In no way am I trying to pick on you, but) Case in point: “Sigils are harder to grok than words” feels like a strong objective claim but… is this actually in any way true? 馬 is a much more complicated symbol than $ or @ or ->, but we have something like 1.5 billion people in the world happily reading and writing in languages that require a knowledge of thousands of such symbols to achieve literacy, and they turn out to somehow show lower rates of dyslexia than in alphabet based languages while doing so!

                                                                                                                                Sigil-y writing systems are indeed actually quite common throughout history, so again we have this thing where what feels like a perfectly simple fact actually looks a heck of a lot like a simple case of familiarity when you scratch it just a little bit. The dominance of a few alphabetic writing systems outside of Asia could simply be a historical accident for all we know – there are no strong results from cognitive science supporting any claim that it’s objectively more fit to “human cognition”. We really don’t have any idea whether words are simpler or more efficient than symbols, or whether python is a global maxima of readability, a local minima, or anything in between. There are almost no good studies proving out any of this, just a lot of handwaving and poorly supported claims based on what people happen to like or be most familiar with.

                                                                                                                                1. 2

                                                                                                                                  馬 is a word. It happens to be written as a single character, but that doesn’t make it punctuation.

                                                                                                                                  1. 2

                                                                                                                                    I’m aware. I speak Japanese.

                                                                                                                                    “Sigil” does not mean “punctuation”. It actually means something like “symbol with occult powers”, but in a programming context I think we can understand it as “symbol that conveys an important functional meaning”, like -> being the symbol meaning “returns a value of the following type”. The point being that OP was being pretty silly when they wrote that it’s a “rule of the human mind” that it’s easier to understand not written out as “not” rather than ! when the existence of a billion plus people using languages with things like “不” at least weakly implies that a single symbol for not is no more mentally taxing to understand.

                                                                                                                                    (that in many programming languages most sigils are punctuation is mostly just an artifact of what’s easy to type on a western keyboard, but it’s by no means the rule. See: APL, which can be chockfull of non-punctuation sigils)

                                                                                                                                    1. 1

                                                                                                                                      The point is that the symbol has a natural pronunciation, which makes it easy to read for a Japanese spsaker. In contrast, when I see !foo or &foo or $foo, my mind just makes an unintelligible noise followed by “foo”, so I have to concentrate on what the symbol means.

                                                                                                                                      1. 1

                                                                                                                                        But these symbols all do have actual pronunciations that are generally specified in the language or are established conventionally, eg) !foo is read “not foo”, &foo is “addressof foo” (at least in C) or “ref foo” in Rust, etc. Good learning resources almost always provide a reading when they introduce the symbol (Blandy et al’s Programming Rust is very good about this, for instance).

                                                                                                                                        Also fwiw not everyone “vocalizes” what they’re reading in their head, that’s actually not a universal thing.

                                                                                                                                  2. 1

                                                                                                                                    When I speak about “understandability” or whatever I’m not making a claim against an abstract Ur-human raised in a vacuum, I’m speaking about humans as they exist today, including cultural and historical influences, and measured on a demographic (macro) scale, rather than an individual (micro) scale. That is, I’m making a descriptive argument, not a normative one. In this context, “familiarity” is I guess a totally reasonable thing to account for! People understand better the things they are familiar with. Right?

                                                                                                                                    1. 3

                                                                                                                                      That is, I’m making a descriptive argument, not a normative one.

                                                                                                                                      It’s not a very good descriptive argument, though, insofar as you’re really failing to describe a lot of things in order to make your argument fit the conclusion that “sigils are harder to grok than words”.

                                                                                                                                      Even if we confine ourselves to Western English speakers… what about mathematics? Why does almost everyone prefer y = x+1 to Cobol’s ADD 1 TO X GIVING Y? It’s more familiar, right? There doesn’t seem to be any long-term push to make Mathematics more wordy over time (most of the established symbols have hung around for hundreds of years and had ample opportunity to get out-competed by more grokkable approaches, if word-based approaches were found by people to be any more grokkable), so if we’re describing the long-term pressures on artificial languages I don’t think “sigils are harder to grok than words” is an accurate descriptive statement.

                                                                                                                                      In this context, “familiarity” is I guess a totally reasonable thing to account for! People understand better the things they are familiar with. Right?

                                                                                                                                      Well, sure. But “in some contexts words are more familiar than sigils to western audiences” is a much different claim than “sigils are harder to grok than words” in any sense, and it leaves a lot more room to talk about sigils in programming languages in a rational way. Things like “dereferencing pointers” aren’t really familiar to anyone in words or sigils, so it’s not obvious to me that x = valueat y is any more or less “correct”/“intuitive”/“grokable” than x = *y.

                                                                                                                                      If anything, given the relative unpopularity of the Pascal/Ada & Cobol language families, a certain amount of “unfamiliar concepts compressed into sigils” seems to be appreciated by programmers at large. But other people disagree, which seems to point at this mostly being a superficial argument over tastes and perhaps how much maths background one has, rather than some kind of concrete and objective variation in any measurable metric of “understandability”.

                                                                                                                                      1. 2

                                                                                                                                        what about mathematics?

                                                                                                                                        Well, I think this substantiates my point? In the sense that way more people can read prose than can understand nontrivial math. Right?

                                                                                                                                        “in some contexts words are more familiar than sigils to western audiences” is a much different claim than “sigils are harder to grok than words”

                                                                                                                                        Not some but most or even almost all, depending on just how many sigils we’re talking about.

                                                                                                                                        Authors generally don’t invent new languages in order to express their literary works; they take the language(s) they already know, with all their capabilities and constraints, and work within those rules. They do this because their goal is generally not to produce the most precise representation of their vision, but instead to produce something which can be effectively consumed by other humans. The same is true of programming.

                                                                                                                                        1. 2

                                                                                                                                          Well, I think this substantiates my point? In the sense that way more people can read prose than can understand nontrivial math. Right?

                                                                                                                                          More people can read prose (in general) than the prose portions of an advanced Mathematics text (in specific). It’s not the orthography of mathematics that’s the limiting factor here.

                                                                                                                                          Authors generally don’t invent new languages in order to express their literary works; they take the language(s) they already know, with all their capabilities and constraints, and work within those rules. They do this because their goal is generally not to produce the most precise representation of their vision, but instead to produce something which can be effectively consumed by other humans. The same is true of programming.

                                                                                                                                          Which speaks to my point. Programming uses “sigils” because in many cases these sigils are already familiar to the audience, or are at least no less familiar to the audience for the concepts involved than anything else would be, and audiences seem to show some marked preference for sigils like { … } vs begin … end, y = x + 1 seems pretty definitely preferred for effective consumption by audiences over ADD 1 TO X GIVING Y, etc.

                                                                                                                                          At any rate, we seem to have wandered totally away from “sigils are objectively less readable” and fully into “it’s all about familiarity”, which was my original point.

                                                                                                                                          1. 2

                                                                                                                                            I’m not claiming that sigils are objectively less readable than prose. I’m objecting to the notion that syntax is a superficial aspect of comprehension.

                                                                                                                                            1. 1

                                                                                                                                              You’ve made claims that terse syntax impedes comprehension (“Sigils are harder to grok than words”), where the reality is in the “it depends” territory.

                                                                                                                                              For novices, mathematical notation is cryptic, so they understand prose better. But experts often prefer mathematical notation over prose, because its precision and terseness makes it easier for them to process and manipulate it. This is despite the fact that the notation is objectively terrible in some cases due to its ad-hoc evolution — even where the direction is right, we tend to get details wrong.

                                                                                                                                              Forms of “compression” for common concepts keep appearing everywhere in human communication (e.g. in spoken languages we have contractions & abbreviations, and keep inventing new words for things instead of describing them using whole phrases), so I don’t think it’s an easy case of “terse bad verbose good”, but a trade-off between unfamiliarity and efficiency of communication.

                                                                                                                                              1. 1

                                                                                                                                                I agree with all of your claims here.

                                                                                                                                              2. 0

                                                                                                                                                . I’m objecting to the notion that syntax is a superficial aspect of comprehension.

                                                                                                                                                It’s not fully, but “the * operator should be spelled valueat/ {} should be spelled begin end” stuff is a superficial complaint unless and until we have objective, measurable reasons to favor one syntactical presentation over the other. Otherwise it’s just bikeshedding preferences.

                                                                                                                                                But I’m sorry, let’s not continue this. I’m not buying the goalpost move here. You wrote that human cognition obeys “well-defined rules. Sigils are harder to grok than words”. That’s pretty obviously a claim that “sigils are objectively less readable than prose” due to these “well defined rules of cognition”. That’s the kind of handwavey, pseudoscience-as-fact discourse I was objecting to and pointing out these discussions are always full of.

                                                                                                                                                I’ve pointed out that this is, in several ways, basically just a load of hot air inconsistent with any number of things true of humans in general (symbol based writing systems) and western readers in specific.

                                                                                                                                                Now your “well-defined rules of human cognition which include that sigils are less readable than words” weren’t trying to be an objective claim about readability?

                                                                                                                                                Sure. I’m done. Have a good one.

                                                                                                                              2. 24

                                                                                                                                I would warmly suggest making an effort to hit Page Down twice to get past the syntax bit and read the rest of the post though, because it’s a pretty good and pragmatic take, based on the author’s experience writing and maintaining a kernel. Xous is a pretty cool microkernel which runs on actual hardware, it’s actually a pretty good test of Rust’s promises in terms of safety and security.

                                                                                                                                1. 10

                                                                                                                                  It’s interesting but also has the weird dichotomy that the only two choices for systems programming are C or Rust. C++ also has a lot of the strengths that the author likes about Rust (easy to write rich generic data structures, for example), and has a bunch of other things that are useful in a kernel, such as support in the standard library for pluggable memory allocators, mechanisms for handling allocation failure, a stable standard library API, and so on.

                                                                                                                                  1. 5

                                                                                                                                    I had exactly the same thought. C++ burnt through a lot of good will in the C++98 era where it was admittedly a hot mess (and all the compilers where buggy dumpster fires). Now on one hand we have people who publicly and loudly swore off touching C++ ever again based on this experience (and even more people parroting the “C++ is a mess” statement without any experience) and on the other the excitement of Rust with all the hype making people invest a large amount of effort into learning it. But the result, as this article shows, is often not all roses. I believe oftentimes the result would have been better if people invested the same amount of time into learning modern C++. Oh well.

                                                                                                                                    1. 5

                                                                                                                                      Writing C++ is like writing Rust but with your whole program wrapped in unsafe{}. You have to manage your memory and hope you did it right.

                                                                                                                                      1. 4

                                                                                                                                        As I hope this article clearly demonstrates, there is a lot more to a language chice than memory safety. Also, FWIW, I write fairly large programs and I don’t find memory management particularly challenging in modern C++. At the same time, I highly doubt that these programs can be rewritten in Rust with the result having comparable performance, compilation times, and portability properties.

                                                                                                                                        1. 1

                                                                                                                                          What would hinder Rust from having comparable performance, compilation times, and portability properties, in your opinion?

                                                                                                                                          1. 1

                                                                                                                                            In summary:

                                                                                                                                            Performance: having to resort to dynamic memory allocations to satisfy borrow checker.

                                                                                                                                            Compilation: in Rust almost everything is a template (parameterized over lifetimes).

                                                                                                                                            Portability: C/C++ toolchain is available out of the box. I also always have an alternative compiler for each platform.

                                                                                                                                      2. 4

                                                                                                                                        string_view of temporaries makes dangling pointers instead of compilation errors. optional allows unchecked dereferencing without warnings, adding more UB to the modern C++. I haven’t met a C++ user who agrees these are fatal design errors. Sorry, but this is not up to safe Rust’s standards. From Rust perspective modern C++ continues to add footguns that Rust was designed to prevent.

                                                                                                                                        1. 1

                                                                                                                                          I haven’t met a C++ user who agrees these are fatal design errors.

                                                                                                                                          I haven’t used string_view much so can’t categorically say it’s not a design error (it very well may be). But for optional I can certainly say it is a trade-off: you have the choice of checked access (optional::value()) or unchecked and you decide what to use. I personally always use unchecked and never had any problems. Probably because I pay attention to what I am writing.

                                                                                                                                          1. 5

                                                                                                                                            This is the difference in approaches of the two languages. In C++ if the code is vulnerable, the blame is on the programmer. In Rust if the code is vulnerable, Rust considers it a failure of the language, and takes responsibility to stop even “bad” programmers from writing vulnerable code. I can’t stress enough how awesome it is that I can be a careless fool, and still write perfectly robust highly multi-threaded code that never crashes.

                                                                                                                                            In terms of capabilities, Rust’s Option is identical, but the the default behavior is safe, and there’s a lot of syntax sugar (match, if let, tons of helper methods) to make the safe usage the preferred option even for “lazy” programmers. The UB-causing version is written unsafe { o.unwrap_unchecked() }, which is deliberately verbose and clunky, so that the dangerous version stands out in code reviews, unlike subtle * or -> that are commonly used everywhere.

                                                                                                                                            Rust’s equivalent of string_view is &str, and it’s practically impossible to use the language without embracing it, and it’s borrow-checked, so it won’t compile if you misuse it.

                                                                                                                                      3. 2

                                                                                                                                        Eh, maybe the author just didn’t write that much low-level/kernel code in C++. I try not to read too much into these things. If I were to start learning F# tomorrow, then tried to write a similar piece two years from now, I’d probably end up with something that would have the weird dichotomy that the only two choices for functional programming are Scheme and F#.

                                                                                                                                        1. 1

                                                                                                                                          Scheme is honestly so hard to do functional in. It’s shockingly imperitive by nature given the reputation.

                                                                                                                                      4. 3

                                                                                                                                        I did read the entire post, but I wanted to voice that focusing on the wrong thing first makes people not take you seriously, especially when the author expresses it doesn’t matter, but they still decided to make it first?

                                                                                                                                        1. 3

                                                                                                                                          I may not be interpreting this correctly but I didn’t take the author qualifying it as a superficial complaint to mean that it doesn’t matter. Based on the issues he mentions regarding the readability of Rust macros, for example, I think it’s superficial as in “superficial velocity”, i.e. occurring or characterising something that occurs at the surface.

                                                                                                                                          (But note that I may be reading too much into it because reviewing and auditing Rust code that uses macros is really not fun so maybe I’m projecting here…)

                                                                                                                                      5. 20

                                                                                                                                        The final sentence of that section said, in summary, “Rust just has a steep learning curve in terms of syntax”. A critical retrospective that does not mention the horrendous syntax or its learning curve would lack credibility.

                                                                                                                                        1. 4

                                                                                                                                          I find Rust’s syntax perfectly clear and sensible. I am not the only one.

                                                                                                                                        2. 9

                                                                                                                                          I liked that it starts with that TBH. Rust’s dense syntax is probably the first impression of the language for many people—it was for me at least. And putting the author’s first impression first in the article makes it read more like a person telling a story, rather then a list of technical observations sorted by importance.

                                                                                                                                          I like to read stories by humans; i feel it easier to connect with the author and therefore to retain some of what they say. YMMV of course.

                                                                                                                                          1. 2

                                                                                                                                            And if they think rust is hard to read, wait until they discover lisp!

                                                                                                                                            (I know this author probably is already familiar with lisp and many other things, but the comparison stands.)

                                                                                                                                            1. 6

                                                                                                                                              I find it the other way around. If you temporarily put aside the issues of special forms and macros, the syntax of Lisp is extremely minimal and regular (it’s almost all lists and atoms). So Lisp stands at kind of an opposite extreme from Rust, with more familiar languages somewhere in between.

                                                                                                                                              1. 5

                                                                                                                                                Nim still has a dumpLisp routine to show you the shape of an AST you may want to manipulate.

                                                                                                                                                Syntax can be very personal, but I strongly prefer Nim’s to Rust’s and see no compelling language feature of Rust to tempt me away, though Nim is not without its own issues.

                                                                                                                                                1. 2

                                                                                                                                                  Nim isn’t really comparable is it? More like Go with a GC etc?

                                                                                                                                                  1. 2

                                                                                                                                                    “How comparable” mostly depends upon what you mean by “a GC etc”. Nim’s (AutomaticRC/OptimizedRC) memory management seems fairly similar to Rust, but I am no Rust expert and most PLs have quite a few choices either directly or ecosystem-wide. (Even C has Boehm.) There is no “GC thread” like Java/Go. The ORC part is for cycle collection. You can statically specify {.acyclic.}, sink, lent, etc. in Nim to help run-time perf. Some links that go into more detail are: https://nim-lang.org/blog/2020/10/15/introduction-to-arc-orc-in-nim.html https://nim-lang.org/blog/2020/12/08/introducing-orc.html

                                                                                                                                                    1. 0

                                                                                                                                                      “Go with a GC” is Go.

                                                                                                                                                      1. 1

                                                                                                                                                        Yes, that’s why I said it

                                                                                                                                                  2. 2

                                                                                                                                                    The complaint in the article is about noisy hard to read though, and lisp is definitely that, even if it is simple and regular that simplicity leads everything to look the same.

                                                                                                                                                    1. 3

                                                                                                                                                      I always wondered why indentation-based reader macros (SRFI-49 is a simple one) never became popular. I can see “whys” for big macro writer types since they often want to pick apart parse trees and this adds friction there. Most programmers are not that (in any language). My best guess is a kind of community dynamic where tastes of village elders make beginners adapt more. Or wishful promises/hopes for beginners to become elders? Or a bit of both/etc.?

                                                                                                                                                      Of course, part of the regularity is “prefix notation” which can remain a complaint.

                                                                                                                                                2. 1

                                                                                                                                                  It makes it hard to take the rest of the post seriously

                                                                                                                                                  As x64k said the post is pretty well made I think and some honest criticism. If anything you can criticize the bad blog layout, which has big white bars on mobile and desktop, giving you a hard time reading it from any device.

                                                                                                                                                1. 4

                                                                                                                                                  Fly plus SQLite plus LiteStream is kind of a game changer for small dynamic apps. The only missing ingredient is an S3 clone from Fly.

                                                                                                                                                  1. 2

                                                                                                                                                    There’s also https://lite.datasette.io for an in browser SQLite browser.

                                                                                                                                                    1. 12

                                                                                                                                                      It’s fashionable to hate XML because it was used in a lot of places it was a bad fit in the 00s, but at least it’s a pretty good document language.

                                                                                                                                                      YAML though is always a bad fit. If you want machine readable config, use JSON; human readable, use TOML. When does YAML ever fit?

                                                                                                                                                      https://mobile.twitter.com/carlmjohnson/status/1372224080749993988

                                                                                                                                                      1. 7

                                                                                                                                                        TOML hasn’t existed as long as YAML. YAML also has a lot of nice features, including whitespace-sensitive (if it’s a feature for Python, it’s definitely one here) which removes a lot of syntax noise. One thing I can’t live without when using it as a configuration language is anchors. Being able to reduce duplication with a feature of the language itself is very nice.

                                                                                                                                                        In all, I’d prefer if apps just used a DSL or published a complete json-schema which lets you use whatever config you want.

                                                                                                                                                        1. 14

                                                                                                                                                          TOML hasn’t existed as long as YAML

                                                                                                                                                          Sure, but people keep using YAML for new things.

                                                                                                                                                          YAML also has a lot of nice features, including whitespace-sensitive (if it’s a feature for Python, it’s definitely one here) which removes a lot of syntax noise.

                                                                                                                                                          Ugh, this is the single thing I hate most about YAML. I can defend Python, but YAML’s whitespace rules are picky and hard to internalize.

                                                                                                                                                          One thing I can’t live without when using it as a configuration language is anchors. Being able to reduce duplication with a feature of the language itself is very nice.

                                                                                                                                                          Cue has a good solution to this, but my top line is that if you really need references (as opposed to their being convenient), the thing you’re doing is essentially programming, and you should use a programming language, not a configuration language.

                                                                                                                                                          In all, I’d prefer if apps just used a DSL or published a complete json-schema which lets you use whatever config you want.

                                                                                                                                                          Caddy has an interesting approach where the canonical format is JSON, and then they make a ton of adaptors so you can use a Caddy specific DSL too and plug it into APIs etc.

                                                                                                                                                          1. 14

                                                                                                                                                            if you really need references … the thing you’re doing is essentially programming

                                                                                                                                                            I disagree. Needing references just means the thing you’re describing is a DAG, and why is that programming when a tree is not? (Hopefully YAML doesn’t let you create loops, but even so that’s still just a directed graph.)

                                                                                                                                                            As a counterexample, RDF lets you describe directed graphs but is definitely a description language not a programming language. You can of course describe RDF in a programming language but that’s not the same thing as RDF itself.

                                                                                                                                                            1. 1

                                                                                                                                                              fwiw I’d argue adjacency lists are easier to read, especially if you’re not familiar with the dark corners of YAML

                                                                                                                                                      1. 16

                                                                                                                                                        Fully agree. I also think it’s important to note that RAII is strictly more powerful than most other models in that they can be implemented in RAII. Some years ago I made this point for implementing defer in Rust: https://code.tvl.fyi/about/fun/defer_rs/README.md

                                                                                                                                                        1. 5

                                                                                                                                                          What other models are you talking about? Off the top of my head, linear types are more powerful; with-macros (cf common lisp) are orthogonal; and unconstrained resource management strategies are also more powerful.

                                                                                                                                                          1. 2

                                                                                                                                                            unconstrained resource management strategies are also more powerful.

                                                                                                                                                            How is that more “powerful” in OP’s sense? Can you implement RAII within the semantics of such a language?

                                                                                                                                                            1. 5

                                                                                                                                                              I should perhaps have said ‘expressive’. There are programs you can write using such semantics that you cannot write using raii.

                                                                                                                                                          2. 2

                                                                                                                                                            That’s interesting, but it wouldn’t work in Go because of garbage collection. You could have a magic finalizer helper, but you wouldn’t be able to guarantee it runs at the end of a scope. For a language with explicit lifetimes though, it’s a great idea.

                                                                                                                                                            1. 11

                                                                                                                                                              Lua (which has GC) has the concept of a “to-be-closed”. If you do:

                                                                                                                                                              local blah <close> = ...
                                                                                                                                                              

                                                                                                                                                              That variable will be reclaimed when it goes out of scope right then and there (no need to wait for GC). Also, if an object has a __close method, it will be called at that time.

                                                                                                                                                              1. 7

                                                                                                                                                                Sounds like the Python with statement.

                                                                                                                                                              2. 8

                                                                                                                                                                It doesn’t have to be such a clear-cut distinction. C# is a GC’d language but also has a using keyword for classes that implement IDispose, which runs their finaliser at the end of a lexical scope. This can be used to implement RAII and to manage the lifetimes of other resources.

                                                                                                                                                                1. 2

                                                                                                                                                                  What do you do when you want the thing to live longer? For the Rust case, you just don’t let the variable drop. For Go, you can deliberately not defer a close/unlock. What do you do in C#?

                                                                                                                                                                  1. 3

                                                                                                                                                                    What do you do in C#?

                                                                                                                                                                    Hold onto a reference, don’t use using.

                                                                                                                                                                    1. 1

                                                                                                                                                                      Ah. Seems a lot like with in Python.

                                                                                                                                                                      1. 1

                                                                                                                                                                        Basically except I believe C# will eventually run Dispose if you don’t do it explicitly unlike Python. I can’t find evidence of when C# introduced using but IDisposable has been there since 1.0 in 2002 while Python introduced with since 2.5 in 2005.

                                                                                                                                                                        1. 2

                                                                                                                                                                          Python explicitly copied several features from C#. I wouldn’t be surprised if with was inspired by using.

                                                                                                                                                                  2. 1

                                                                                                                                                                    That’s a nice approach. Wish more languages would do something like this.

                                                                                                                                                                    1. 2

                                                                                                                                                                      It still suffers from the point in the article where you don’t know who held a reference to your closeable thing and it’s not always super clear what is IDisposable in the tooling. I think VS makes you run the code analytics (whatever the full code scan is called) to see them.

                                                                                                                                                                      1. 5

                                                                                                                                                                        Has anyone written a language where stack / manual allocation is the default but GC’d allocations are there if you want them?

                                                                                                                                                                        It seems mainstream programming jumped to GC-all-the-things back in the 90s with Java/C# in response to the endless problems commercial outfits had with C/C++, but they seem to have thrown the proverbial baby out with the bathwater in the process. RAII is fantastic & it wasn’t until Rust came along & nicked it from C++ that anyone else really sat up & took notice.

                                                                                                                                                                        1. 2

                                                                                                                                                                          Has anyone written a language where stack / manual allocation is the default but GC’d allocations are there if you want them?

                                                                                                                                                                          D?

                                                                                                                                                              1. 2

                                                                                                                                                                We pretend to work. They pretend to pay us.

                                                                                                                                                                1. 1

                                                                                                                                                                  Neat. I’ve long thought there should be some simple workbook computers that have graph paper as “memory” and have you start at A1 and follow the instructions to draw shapes or some such. Maybe something like ✎A10-Z10 to mean draw a line from A10 to Z10 and then some instructions for branching and adding.

                                                                                                                                                                  1. 2

                                                                                                                                                                    In JavaScript you’d use const most of the time because it’s immutable.

                                                                                                                                                                    This is wrong. The whole problem with const in JS is that it is mutable.

                                                                                                                                                                    1. 4

                                                                                                                                                                      To be fair, JS is not unique in this — const has advisory or even aspirational status in some other languages, too.

                                                                                                                                                                      1. 1

                                                                                                                                                                        It does conflate reassignment with mutation, but the convention is nevertheless a common one, regardless of whether one agrees with it.

                                                                                                                                                                        1. 1

                                                                                                                                                                          Well, I think that rule is dumb because it leads to the misunderstanding that this article perpetuates. But whether prefering const is good or bad, it is very important to state explicitly that const in JS is not immutable. It is mutable but not reassignable. JS has Object.freeze which actually does create immutable objects.

                                                                                                                                                                      1. 3

                                                                                                                                                                        The way programs are written today is different from 5 years ago, 10 years ago, 20 years ago, 30 years ago. If you’re in Javascript land, what you’re writing today probably doesn’t even match what you wrote 2 years ago. In some ways, that’s terrifying.

                                                                                                                                                                        Thankfully this is not the case with C (since most people target C99 or even older) and I think that’s part of the charm with that community.

                                                                                                                                                                        1. 5

                                                                                                                                                                          That’s true! And there’s something wonderful about consistency, too. Being able to ensure that your programs will work years from now is often done by the language team rather than individual developers, but figuring out how to write code that works across, say, es5 and es2022, or Python 2.7 and 3.6 is rewarding in its own way

                                                                                                                                                                          1. 1

                                                                                                                                                                            I met a woman who wrote code for the Pluto New Horizons probe. Her code had to last for nine years in transit through space. Most website code gets thrown out every five years after the fashions change. :-)

                                                                                                                                                                            1. 3

                                                                                                                                                                              Orbital mechanics don’t change as much as most business requirements.