Threads for habibalamin

    1. 8

      One issue that these config rants never address is the distinction between user authored config files and program managed ones which are basically state.

      The config files that I actually care about are things like ~/.emacs and ~/.zshrc that I carefully maintain over many years. I don’t want to mix them in with the ephemeral junk that lives under .config.

      1. 11

        The XDG Base Directory specification does distinguish between user-authored config files, which are supposed to go in ~/.config by default, and state, ~/.local/state by default. I’m not sure why you say these rants don’t address the distinction when pretty much all of them, including this one, mention that spec and argue for its adoption.

        Honestly, I’d even go just a tad further and advocate for a subdirectory per app (for any given directory, like .config, that’s used) just for forward compatibility if another file is added (like Vim and other software uses).

        1. 1

          I’m experimenting with export XDG_CONFIG_HOME=~/etc! Makes a lost of sense! Or how about $XDG_CACHE_HOME in ~/var/cache. Just mirror the root / file hierarchy in your $HOME.

      2. 3

        My solution to this has been to store the files I really care about in some non-standardized directory (I’m on macOS, so I use ~/Library/Dotfiles) and then write a script to symlink ~/Library/Dotfiles/zshrc to ~/.zshrc and so on. The advantage is that the symlinks are clearly differentiated when I list my home directory. The downside is that the script has a lot of special cases, like for Vim and Firefox, which both have more complicated configurations than “single file within the home directory.”

        1. 1

          My one of these ended up turning into a templating pseudo-devops-tool. Do not recommend, time would’ve been better spent learning Nix or something.

    2. 3

      Looks like Hirrolot forgot about OCaml and its type-safe printf implemented mostly at the library level, with vastly better error messages:

      utop # Printf.printf "Mr. John has %d contacts in %s" "New York";;
      Error: This expression has type string but an expression was expected of type
      1. 4

        type-safe printf implemented mostly at the library level

        It is not. Type-checker treats the string literal specially if it is an argument to printf family of functions. Essentially, this is string interpolation with worse ergonomics and layering violation between syntax and type checking.

        Still an ok practical solution though!

        1. 1

          Yes the string literal is parsed as a format literal in some cases, but after the parsing is done, the checking of the type-safety of the arguments is all implemented at the library level, in CamlInternalFormat* modules.

      2. 3

        Is that a good error message? It’s not indicating in any way which part of the expression is the problem, and the actual problem is that the number of parameters is too small, not that the last parameter has a wrong type. It’s better than “something went wrong” but still pretty bad.

        This is much better error message:

        1. 2

          I mean, it’s probably partially applied, so there’s no such thing as too few parameters.

          On the other hand, the first argument must be a number, but here, it’s clearly a string.

          So even if we ignore the partial application and assume it does have too few parameters, it’s not just about that, otherwise the caller would just add another argument to the end, which clearly wouldn’t fix the problem.

          I would say the error message is correct, though not precise enough.

          1. 1

            The error message is correct, I’m not saying it’s incorrect.

            The fact that it is partially applied doesn’t change anything from the pov of the end user. You can’t fix compilation by changing the type of parameter, only by adding one more parameter. This is the fundamental problem here and it’s not mentioned in the error message. This makes that error message technically correct yet much less useful than the example I’ve linked.

            1. 1

              I don’t think that’s any more the “fundamental” problem than the Turing machine or lambda calculus are the “fundamental” models of computation.

              Or you know how Git sometimes shows a diff of adding a function B after existing function A as adding a closing brace to function A that already had one and then not adding a closing brace to function B?

              I appreciate that there’s a more correct answer from a human POV, but fundamentality isn’t the issue here.

              You can’t fix compilation by changing the type of parameter

              You literally can, though. An argument was given in position one, which takes an int, and no argument was given in position two, which is not an error, as the function is curried.

              The issue here isn’t what the error is, it’s detecting what the user possibly meant and suggesting a possible fix that’s more in line with exactly where they mostly likely slipped up instead of just choosing the smallest distance change, which are actually extra features that come with tradeoffs. But yes, if they can pull it off, the errors would be much better.

              You’re right, you didn’t question its correctness, you questioned if it’s good.

              The precise bar for attaining a score of good is subjective, but in the context of a type-safe printf implementation, this is vastly better than the language it was being compared to. It makes the printf function error messages as good as normal functions’ in the language.

              In my eyes, it’s good even outside of that context. Is it amazing? No. But very few error messages are.

              This makes that error message technically correct yet much less useful than the example I’ve linked.

              Your example has the exact same problem. It shows two errors. The first:

              error: 2 positional arguments in format string, but there is 1 argument

              would be completely incorrect in the OCaml example.

              But worse, your Rust error message has the exact equivalent of the problem you’re complaining about in the OCaml:

              error[E0277]: SomeArbitraryDebugPrintableThing doesn’t implement std::fmt::Display

              I looked it up, and AFAICT, {:?} in format strings is for std::fmt::Display and {} for core::fmt::Debug.

              So even the Rust here isn’t saying, “oh, SomeArbitraryDebugPrintableThing has trait core::fmt::Debug, so maybe you were targeting the {:?} instead of the {} and you just need to put an argument with std::fmt::Display before it in position one to target the {}”.

              It’s complaining about the lack of std::fmt::Display for SomeArbitraryDebugPrintableThing instead, which it thinks the user is targeting position one with, which is clearly the equivalent problem as the OCaml error.

        2. 2

          That’s the output of the REPL, and the highlighting of the specific part of the expression is lost in copy-paste because it’s an underlining code that terminals support but plain text formats don’t. Here’s the output of the OCaml compiler:

          File "./", line 1, characters 56-66:
          1 | let () = Printf.printf "Mr. John has %d contacts in %s" "New York"
          Error: This expression has type string but an expression was expected of type

          the actual problem is that the number of parameters is too small, not that the last parameter has a wrong type

          In languages with automatic currying and partial application of functions, you will almost always get this kind of slightly-off error whenever you pass in too few arguments. Technically, it is correct. At this point of the function application, you need to apply an int. After you do that, you’ll get a different error which will guide you further:

          File "./", line 1, characters 9-58:
          1 | let () = Printf.printf "Mr. John has %d contacts in %s" 42
          Warning 5 [ignored-partial-application]: this function application is partial,
          maybe some arguments are missing.
          File "./", line 1, characters 9-58:
          1 | let () = Printf.printf "Mr. John has %d contacts in %s" 42
          Error: This expression has type string -> unit
                 but an expression was expected of type unit

          The point is that the errors are much better than what you see in the more esoteric languages.

      3. 2

        I suspect that in Ocaml and F# printf is simply magic, similarly to Rust

        1. 2

          It is magic in OCaml and F# — the rules for parsing formatted string literal are hard-coded into the compiler. This is similar to string intepolation syntax, except that instead of dedicated syntax, you get “string literal in a position that expects formatter”. In other words, string literals are polymorphic — they can denote either the string, or a formatter. Compiler chooses between two interepretation based on the expected type.

          In Rust, format strings are not magic. They are macros, and can be implemented completely in user-space. Eg, I do this here. But they are marcos, so call-site looks ugly.

          1. 1

            In Rust, format strings are not magic. They are macros, and can be implemented completely in user-space.

            Is that true now? I was under the impression that non-magic procedural macros can’t yet provide error messages as detailed as the standard format macros’.

      4. 1

        I believe that F# also has a type safe printf. (I know that F# was originally a clone of OCaml.)

        How does OCaml achieve type safety here?

        1. 2

          Cool. I don’t know how F# does it but OCaml does it with a mix of special-casing parsing of format strings, and a bunch of support code in the standard library to implement the type safety, more details here:

    3. 1

      I found this to be a really robust piece of work, and the comments to be quite depressing.

      1. 1

        I found the comments quite fair mostly, but there were a few that were 1) based on ignorance, 2) trolls, 3) making a point already addressed by the post, or 4) just plain dumb. I was also a little dispirited reading some of them, but there’s not much point dwelling on them, especially when they were mostly responded to.

        As for the research, it was solid. There was room for improvement, for sure, but a great start and far better than some others I’ve seen out there. I hope it serves as inspiration to build on.

    4. 4

      I always set up so that option-left, option-right, option-up, and option-down trigger the right meta sequences to move by one word/to the beginning/end of the line, like a normal Mac app. It should be the default.

      1. 2

        Does that require option is meta? I always turn that off so that I can easily enter accented characters in vim.

        1. 1

          I always turn that off so that I can easily enter accented characters in vim.

          And I always turned it on so I could use Meta+[0-9qwertyuio] in irssi 😬

          1. 1

            Have both, with my app Metalt. Converts left-alt and $KEY to esc then key, which interprets as Meta and $KEY. Leaves right-alt alone.

        2. 1

          No, it does not.

    5. 7

      Here’s an interesting detail that I feel should have been hinted at in the headline, and would have made me far more likely to click without being clickbait, and while leaving some interesting meat in the body that would have made the read worthwhile in my opinion:

      Amateur exploited weakness in systems that have otherwise dominated grandmasters.


      The tactics that put a human back on top on the Go board were suggested by a computer program that had probed the AI systems looking for weaknesses. The suggested plan was then ruthlessly delivered by Pelrine.

      “It was surprisingly easy for us to exploit this system,” said Adam Gleave […]

      The winning strategy revealed by the software “is not completely trivial but it’s not super-difficult” for a human to learn and could be used by an intermediate-level player to beat the machines, said Pelrine.

      Perhaps we could edit the title to something like, “Amateur demolishes top Go AI with simple tactic discovered by computer program”. Maybe there’s a more elegant way to say it.

      1. 14

        Perhaps we could edit the title to something like, “Amateur demolishes top Go AI with simple tactic discovered by computer program”. Maybe there’s a more elegant way to say it.

        “AI discovered way to beat another AI. In order to remain hidden, it trained it’s human minion to do it”

      2. 3

        Would’ve you preferred the original AlphaGO victory described as “A computer beats human at Go with a method devised by another human”?

        1. 1

          No. We’re talking about the Go strategy, which was ‘devised’ by the machine, in both cases (that’s literally the point of AI).

          Yes, AI was devised by humans, but I don’t think any person who read about the original victory was confused about whether a non-human might have devised AI, before or after they read any articles or headlines.

          1. 2

            The noteworthy thing isn’t that humans beat AI or that an AI devised the method, it’s that AlphaGo had a weakness so glaring even a human could exploit it. It’s unlikely that we’d find such a weakness in, say, a “traditional” chess AI which uses opening books and alpha-beta pruning.

            1. 1

              The noteworthy thing isn’t that humans beat AI or that an AI devised the method, it’s that AlphaGo had a weakness so glaring even a human could exploit it.

              I’m not sure what the meaningful distinction is. That’s what I was trying to get at. It’s interesting that an amateur human was able to reliably beat a top Go AI (14 out of 15 times) with a relatively simple tactic.

              These facts are the very same ones I was highlighting in my initial comment, and I was highlighting them because it shows how glaring the weakness was.

              But then some commenters made some points responding to my side point about how these facts probably should have been called out in the headline and I was responding to that.

              I agree with you, this is interesting, because, to go even further, it shows that, with some creativity and time, humans could probably still find some low-hanging fruit to advance certain games where we previously thought AI had picked all of those.

      3. 3

        It’s the policy of to roll with the original title:

        Do not editorialize story titles, but when the original story’s title has no context or is unclear, please change it.

        In this particular case, a much nicer solution would have been to post the paper, rather than the article. Paper’s title is on point:

        Adversarial Policies Beat Superhuman Go AIs

        1. 6

          I think the paper’s title buries the lede a bit - “AI beats other AI” isn’t newsworthy, “there’s a human-viable strategy to beat AI (that happened to be found by another AI)” is an interesting discovery about the limits of superhuman-seeming AI

        2. 3

          That paper title would almost certainly have not gotten me to click on it. It’s even worse than the current article title, even.

          I can only speak for myself, of course.

          1. 2

            The paper’s goal is to inform, not to compel your click. If you require your information sources to be compelling, you will have limited information.

            1. 1

              I’m not suggesting the paper authors should retitle their paper, we’re talking about this in the context of a headline.

              I’m fine with having limited information on AI. I’m not an AI researcher nor do I know what an “adversarial policy” is in the context of AI. This site is full of (technical) laypeople like myself who don’t care for every AI paper, but definitely care about significant advancements in AI understanding, such as a human beating a top AI at Go, and doubly so if the human is an amateur.

              This is a technical community which aggregates links around certain technical topics that they find interesting and think others will, too. We don’t just post every paper that is technical here, even though you could do that if you wanted to.

              If you’re an AI researcher, or some other person who needs “un”limited information for your purposes, fine, you can click on the uninteresting links as well as the interesting links, what I’m suggesting has no impact on you. I’m sure there are even other sites that aggregate papers that aren’t about how interesting the findings are.

              You can be here as well, I’m not saying to go away. But for this site, there is definitely a purpose in making a title compelling. And I’m not saying make every title compelling; if there’s nothing interesting (for a particular definition of interesting) on the other side of a link, no need to trick people into thinking there is.

              There are many reasons a link might be worth a click to different audiences without being ‘interesting’. However, if you’re posting on, your audience is generally a lot of laypeople, and for them, if there’s something interesting about what the link points to, I wouldn’t hide it.

              And none of what I’m saying goes against making titles informative, in fact, I’m advocating for not burying the lede, a lede which is not just interesting, but actually hella informational; the fact that the human who beat the AI is an amateur, even if the strategy was derived by a computer.

    6. 14

      Folks seriously need to remember that they have the right to patch and fork. Open source makes no sense without it.

      The safety valve for bad changes is not abuse, it’s the big prominent “fork” button on the top of the repo page.

      1. 15

        This is mostly easy to say, but hard to do. Yes I can fork a project and reverse the commit which removed the one feature I want, but what then? I now have a project I don’t know the code and the history. Sometimes I don’t even can the language the project is written. Also many project tend to become huge monsters and even some project with a “small” in the description have more then 10.000 lines of code.

        Also forking is sometimes not the solution. Best example for this is JPEG XL support in chrome/ium. Yes I could fork chromium and enable this feature by default. But this wouldn’t help the users which want it, because they want to add JPEG XL images to there website.

        So sometimes it’s frustrating, when software become subjective worse and you can’t do something about it.

        1. 16

          There are two options: fork it, or use your people skills to try to persuade people with commit access that it should be the way you want. People skills being at a deficit in our field, many choose option C: hurl abuse at any available target.

          1. 5

            You forgot a third option: you can use money to persuade those people (or anyone!) to maintain a version that you want.

            Buying services is the way most of our economy works. We’re so used to FOSS being free-of-cost that it sometimes doesn’t even occur to us to pay for it.

            1. 3

              Good point! I wonder how much I’d have to pay to bribe the average open source maintainer to accept my PR.

          2. 3

            I’m not sure people skills are at a deficit any more than any other section of society. Perhaps we have different social customs and norms, with different failings, yes, but I daresay non-developers could learn a social skill or two from developers, not just vice versa.

            1. 4

              I get what you’re trying to say, and yeah there are issues in neurotypical-style social interaction as well. A lot of this animosity we see in FOSS does come from the inability to accept ones’ thoughts & preferences as non-objective though. Nearly everybody is not half as rational as they think they are.

              1. 2

                I’m not gonna argue with you on that, but abuse and entitlement in my experience are fairly universal, with only the methods and other details differing. [What follows is just going off on tangents]:

                Maybe it is higher in software, but I think most people who say that are going more off confirmation bias of stereotypes of developers as blunt, grouchy, driven more by reality than sentimentality which is compounded due to a lifetime of interacting with uncompromising machines, etc., than any real insight;

                1) I think this can make people think non-developers have little or no social skills to learn from developers, and 2) it can make people think developers are some super-rational people who are just above non-developers in logical thinking (in a way that can’t be learned).

                I don’t want to push the other unsubstantiated ideas of “anyone can be a programmer (and even as easily as any other)”, or “any sample of humans organised around an activity share exactly the same traits as any other sample of humans organised around another activity” either, I don’t believe that.

                Rationality is more than just logical thinking, people who organise themselves around rational thinking may tend to have gaps in their rational thinking that other people don’t, and people who organise around empathy may tend to have gaps in their empathetic operation that other people don’t.

                These tangents may seem like obvious ideas, but whatever, I got them off my chest.

          3. 2

            It very much goes both ways. Some people will shut down any discussion (as in, lock the subject in the issue tracker), no matter how civilised. Or will dismiss you for not knowing the group jargon, in-jokes, and the like, rather than welcoming a new contributor.

        2. 4

          True, but browsers are a pretty degenerate case because of just how painful they are to work on.

          Firefox has made some questionable decisions, and as expected, we’ve seen a bunch of forks that reverted them. I’m writing this comment on a Firefox fork.

          1. 2

            As someone who is not terribly enthusiastic about firefox’s poor decisions, what fork are you using?

            1. 2

              Waterfox Classic, because it’s the only one that lets me run TabMixPlus. Using a browser without multi-row tabs isn’t worth it for me anymore. Sometimes websites break, but on average it actually breaks less than “current Firefox hacked to allow loading TabMixPlus via Legacy Extensions Loader”, which I also run in case some site doesn’t like old Firefox anymore. (It’s “good” to know that Firefox could allow running TMP again at any time they wanted. Real worthwhile change, guys.) I have Adobe Flash running on it too.

    7. 13

      Wine is quite honestly, one of the most impressive open source projects in existence. It’s even more impressive when you realize this is made entirely through black-box RE - which of course makes sense, as they gotta avoid being in a not-so-legal area, but that doesn’t make it any less impressive.

      Is there any way I can support the main developers? I can’t really do much right now, but I’d love to support developers once I have a stable source of income again.

      1. 1

        Maybe you can contact one of the people here.

    8. 13

      This is still frighteningly common. Untyped (or at best integer) duration parameters, writing “kilobytes” when we mean “kibibytes”, datetimes without a time zone or TZDB version number.

      1. 9

        Which codebases actually use different types for pennies and dollars, or minutes and seconds? I’ve never seen it in real life.

        I’d guess that approximately 100% of codebases we use from day to day (including say don’t have such a distinction in the type system. They use integers or floats. I’d be interested to learn otherwise.

        While it’s admirable that the author dove into some code she didn’t “own” or understand, I’d also say that the code lacked tests. Whenever I fix a bug, the first thing I do is write a test to reproduce it and fails. Then verify that the fix makes it pass. This seems obvious, but I still see a lot of people “reading and hoping” rather than testing.

        1. 12

          I don’t think that creating distinct types for “dollars” and “pennies” is a very good idea, although I realize this is the fix that the article proposes.

          The codebases I have worked on that handle money use an opaque type for “quantity of money,” with constructors for creating these quantities out of pennies or out of dollars or whatever. Same with time spans – that way you never write a function that says “I need this argument in milliseconds,” you write a function that says “I need a time span,” and the caller can decide how it wants to give you one. The type represents the logical thing you’re measuring, not the specific unit that you measure it with, and all unit conversions go through the opaque type interface.

          Of course it’s still possible to make mistakes, and write code like time_span_of_ms(time_span_to_minutes(span)), but I claim without evidence that that sort of code would stick out like a sore thumb. Generally the only time you leave the safe confines of the opaque type is on the edges of your program, when you’re interacting with the outside world or a third-party API, and that code is going to receive a lot of scrutiny and test attention.

          1. 3

            OK having a separate type for all money sounds a lot more reasonable. So you’re using operator overloading in those codebases?

            But yeah that is not what the original article suggests.

            1. 6

              Yeah, as one example adding two quantities of money uses an overloaded +. But it’s not like a transparent “numeric” interface thing – you can’t multiply two quantities of money, for example, or divide by a quantity of money. (You can divide a quantity of money by a quantity and arrive at a price, but those are separate types because you really don’t want to be able to mix them up, and this operation is not spelled /.)

              1. 1

                Custom infix operators plus abstract type allow to do that easily, e.g., make a *$ operator for multiplying an opaque type for money by an integer. E.g., in OCaml:

                module type MONEY = sig
                  type t
                  val ( +$ ) :t ->  t -> t
                  val ( *$ ) : t -> int -> t
                  val from_int : int -> t
                  val to_int : t -> int
                module Money : MONEY = struct
                  type t = int
                  let ( +$ ) l r = l + r
                  let ( *$ ) amount multiplier = amount * multiplier
                  let from_int amount = amount  
                  let to_int amount = amount

                Since OCaml has local module opening (let open Money in (Money.from_int 10) *$ 2), one could as well reuse *, but a distinct *$ name makes it safe to open the module in a wider context.

                1. 1

                  Calling the constructor from_int just moves the problem up the stack.

                  1. 3
                    1. Conversion of raw inputs to money is doomed to have to be done somewhere, so I’m not sure what’s your point.
                    2. Any constructor is better than using raw ints to mean money because it’s easy to find where that conversion happens.
                    3. I’m talking about an interface to the money type that would allow convenient but safe way to calculate prices, which is a distinct problem.
                    1. 2

                      Yeah, you can implement custom operators to do whatever you want. I claim that that is just not an operation that I want to do very often, so I don’t want it to be very easy to do. It’s like a code smell – did you really mean to multiply dollars? You probably meant to multiply by a price – a distinct type – to arrive at a “quantity of dollars.” There might be cases where you actually want to scale an amount of money (duplicating a transaction multiple times…?) but I would rather have to reach for a named function that makes it very clear why I’m doing that.

                      Regarding to_int/of_int, to my original point I would not write those functions in my code. I don’t know what they do; they seem scary. I would write to_pennies and of_dollars and similar functions, that act over some fixed-precision type (i.e. not integers, since you often want to represent sub-penny values). Internally, sure, you probably represent Money.t as some integral quantity, but I don’t want my application to be able to observe that implementation.

                      1. 1

                        Why would you have different types for prices and quantities of money? How would they differ?

                        1. 4

                          Helps you catch mistakes. Physically, they’re the same, but the more explicit you are in the type system the less likely it is that you’ll accidentally forget to multiply out a price. Mistakes can be very expensive when you’re working with money!

                          1. 3

                            Haven’t thought about this before, but if I draw an analogy to distance. A price is like a rate while a quantity of money is like a distance. You want separate unis got $ and $/ea for the same reason you want separate units for km and km/hr.

                    2. 1

                      Sorry, when I say “calling _ _”, I mean “naming _ _” or “referring to _ as _”. I just mean it could probably have a name that will reduce mistakes in construction, like from_pennies or from_smallest_subunits or something.

                      You’re right that regardless of the name, having a single source of truth constructor is still better. And yes, it wasn’t entirely relevant to the issue of calculating prices, but it’s relevant to the broader thread topic of practices that will help avoid mistakes.

          2. 2

            A nice thing about Go is that pretty much any function that deals with durations takes a time.Duration instance. Poor JavaScript is stuck with window.setTimeout that uses milliseconds. Python actually has a timedelta class, but my experience very few functions actually accept one, which sucks.

            1. 1

              The problem is that Durations are limited to 200 years and Duration*Duration makes no sense but is required.

              1. 1

                Have you run into a use for Durations longer than 200 years? My main experience is that if you subtract a current Time from a zero Time or vice versa, you get back a saturated Duration (which led to me adding Duration.Abs() after I hit a bug with naively trying to convert the minimum duration to a positive number), but I don’t have any use for durations longer than the few years in which my databases have been running.

                1. 2

                  Sure. How old is the Magna Carta? When will the US Sextacentennial be? (In fairness, it’s 290ish years, not 200)

                  I’m more bothered by division and multiplication.

                  1. 3

                    You can’t represent the signing of the Magna Carta in time.Time because it doesn’t know about 🙂

        2. 6

          There are duration data types in most mainstream OO languages, like Java and Python. Alternatively, there’s Hungarian notation, as in duration_millis. For money there’s, for example, Currency in Java or, again, Hungarian notation if that’s not available. The lack of these are either lack of foresight, laziness, or overzealous variable shortening.

          To be clear, you don’t need different types for different multiples of the same unit; having a Pennies class and a Dollars class would just be wasteful.

          1. 2

            I think what you’re suggesting is reasonable, but the original article wrote something different:

            If that function had demanded a type called “dollars” and the caller had another one called “pennies”, it simply would not have passed the type checker/compiler.

            Agree about instant vs. duration being different types.

        3. 5

          I used to work at a company that worked with cryptocurrency, and that had code that assumed that numeric types represented amounts denominated in whatever cryptocurrency asset was specified in another field. Often these numeric types were Python floats, which was itself a problem - currency values should never be represented as a floating-point number!

          At one point, I needed to write some code that worked more closely with the Ethereum ecosystem, where it’s common to represent amounts as integer numbers of wei. A wei is 1.0*10^-18 of an ETH, so 1) reasonable values of currency would not fit into a float without risking losing precision, and 2) it would be disastrous if we ever used a numeric value representing wei in a context where ether was expected. I was paranoid that I’d screw this up somehow and tried to fix the representation of currency amounts everywhere in the codebase to minimize the chance of misusing a numeric value (and while I was at it, got rid of every place we represented a currency amount with a float since that was never correct to begin with). Anyway, another reason why programmers should use programming languages that allow them to easily create new types that will allow the compiler to protect them from themselves.

        4. 4

          I think you might be misunderstanding the idea. The idea isn’t that pennies and dollars are different types, but that you have a Money class and then you create your credit like ad_credit = Money(250, 'USD'). You have to feed the values into constructors with clear intentions and then can use those objects to shift stuff around.

          It’s a similar problem to untrusted input. You do only have “raw” numbers or bytes at the start and end of your codebase, so the instant you receive untrusted input you sanitize/validate/whatever, and end up with useful business logic in 95% of your code. End result is you don’t have to be “careful” all over.

          Other recent example is that Rust will accept Duration and you do things like sleep(Duration::from_milliseconds(500)).

          I think none of this is extremely modern or niche though. Simple stuff like timestamp manipulation will often be done by passing this stuff into a date library first

          1. 2

            The idea isn’t that pennies and dollars are different types

            That’s what is suggested in the article:

            If that function had demanded a type called “dollars” and the caller had another one called “pennies”, it simply would not have passed the type checker/compiler.

            What I’m saying is that that this solution isn’t common. I’d also doubt that it’s a good solution. Some things require testing and types are limited.

            Instants and durations should indeed be different types; that’s a different argument.

        5. 2

          Which codebases actually use different types for pennies and dollars, or minutes and seconds? I’ve never seen it in real life.

          Most of the codebases I see at $WORK do this, but that’s probably because they’re written in Ada, which makes defining new numerical types easy and whose users have a culture of defining new numerical types for the different things they represent.

          I’ve also seen it in one of our internal Ocaml codebases, where we have different string types to represent absolute paths, relative paths and so on.

        6. 1

          a reasonable middle ground that I have seen real life code use is to forbid positional arguments, and have your keyword argument named something like duration_ms so it’s clear what is expected.

    9. 28

      Ditto Scuttlebutt. Which I tried a few years ago but found the UI awful (in the default app at least), and more significantly, it was a resource hog. Just joining one ‘pub’ and following a few people resulted in a half gigabyte of data downloaded, and the app kept re-indexing over and over.

      Anyway, long story short, I’ve been building my own distributed system, Tendril, with a lot of influence from Scuttlebutt but with more efficient data structures & protocols, plus the core is C++ instead of JS and it uses SQLite instead of some bespoke JS database.

      I’ve been honestly procrastinating opening it up, adding “just one more feature” instead, but I’m super close now. I just uploaded the iPad version to TestFlight today (there’s also a Mac app and a bare CLI version that runs on Linux with a browser-based UI.)

      I guess I’ve just outed myself without thinking ahead :) It does seem like a good moment to be unveiling this. Anyway, message me privately if you want an invite.

      1. 3

        I would like to be notified when you have a site up explaining it. I may ask for an invite then.

    10. 83

      I feel like this entire post reinforces just how difficult Python dependency management is. I’m a huge fan of Python, despite all of its flaws, but the dependency management is horrible compared to other languages. Nobody should have to learn the intricacies of their build tools in order to build a system, nor should we have to memorize a ton of flags just for the tools to work right. And this isn’t even going into the issue where building a Python package just doesn’t work, even if you follow the directions in a README, simply because of how much is going on. It is incredibly hard to debug, and that is for just getting started on a project (and who knows what subtle versioning mistakes exist once it does build).

      I think Cargo/Rust really showed just how simple dependency management can be. There are no special flags, it just works, and there are two tools (Cargo and rustup) each with one or two commands you have to remember. I have yet to find a Rust project I can’t build first try with Cargo build. Until Python gets to that point, and poetry is definitely going down the right path, then Python’s reputation as having terrible dependency management is well deserved.

      1. 20

        Completely agree. I’ve been writing Python for 15 years professionally, and it’s a form of psychological abuse to keep telling people that their problems are imaginary and solved by switching to yet another new dependency manager, which merely has a different set of hidden pitfalls (that one only uncovers after spending considerable time and energy exploring).

        Every colleague I’ve worked with in the Python space kind of feels jaded by anyone who promises some tool or technology can make life better, because they’ve been so jaded by this kind of thing in Python (not just dependency management, but false promises about how “just rewrite the slow bits in C/Numpy/multiprocessing/etc” will improve performance and other such things)–they often really can’t believe that other languages (e.g., Go, Rust, etc) don’t have their own considerable pitfalls. Programmers who work exclusively in Python kind of seem to have trust issues, and understandably so.

      2. 13

        The problem is that no matter how good Poetry gets, it still has to deal with deficiencies that exist in the ecosystem. For example, having lockfiles are great, but they don’t help you if the packages themselves specify poor/incorrect package version bounds when you come to refresh your lockfiles (and this is something I’ve been bitten by personally).

        1. 11

          That’s not a python-specific issue though. It’s not even python-like issue. You’ll have the same problem with autoconf / go.mod / cargo / any other system where people have to define version bounds.

          1. 21

            if I create a go.mod in my repo and you clone that repo and run “go build” you will use the exact same dependencies I used and you cannot bypass that. I cannot forget to add dependencies, I cannot forget to lock them, you cannot accidentally pick up dependencies that are already present on your system

            1. 15

              Keep in mind that Go and Rust get to basically ignore the difficulty here by being static-linking-only. So they can download an isolated set of dependencies at compile time, and then never need them again. Python’s import statement is effectively dynamic linking, and thus requires the dependencies to exist and be resolvable at runtime. And because it’s a Unix-y language from the 90s, it historically defaulted to a single system-wide shared location for that, which opens the way for installation of one project’s dependencies to conflict with installation of another’s.

              Python’s venv is an attempt to emulate the isolation that statically-linked languages get for free.

              1. 4

                I described the situation for Go during build time, not during runtime.

                1. 3

                  And my point is that a lot of the things people complain about are not build-time issues, and that Go gets to sidestep them by being statically linked and not having to continue to resolve dependencies at runtime.

                  1. 2

                    I don’t get the importance of distinguishing when linking happens. Are there things possible at build time that are not possible at runtime?

                    1. 7

                      Isolation at build time is extremely easy – it can be as simple as just downloading everything into a subdirectory of wherever a project’s build is running. And then you can throw all that stuff away as soon as the build is done, and never have to worry about it again.

                      Isolation at runtime is far from trivial. Do you give each project its own permanent isolated location to put copies of its runtime dependencies? Do you try to create a shared location which will be accessed by multiple projects (and thus may break if their dependencies conflict with each other)?

                      So with runtime dynamic linking you could, to take one of your original examples, “accidentally pick up” things that were already on the system, if the system uses a shared location for the runtime dynamically-linked dependencies. This is not somehow a unique-to-Python problem – it’s the exact same problem as “DLL hell”, “JAR hell”, etc.

                      1. 4

                        Isolation at runtime is far from trivial. Do you give each project its own permanent isolated location to put copies of its runtime dependencies? Do you try to create a shared location which will be accessed by multiple projects (and thus may break if their dependencies conflict with each other)?

                        But the same issues exist with managing the source of dependencies during build time.

                        1. 4

                          Yeah, I’m not seeing anything different here. The problem is hard, but foisting it on users is worse.

                          The project-specific sandbox vs disk space usage recurs in compiled langs, and is endemic to any dependency management system that does not make strong guarantees about versioning.

                        2. 3

                          No, because at build time you only are dealing with one project’s dependencies. You can download them into an isolated directory, use them for the build, then delete them, and you’re good.

                          At runtime you may have dozens of different projects each wanting to dynamically load their own set of dependencies, and there may not be a single solvable set of dependencies that can satisfy all of them simultaneously.

                          1. 1

                            You can put them into an isolated directory at runtime, that’s literally what virtualenv, Bundler’s deployment mode or NPM do.

                            And at build time you don’t have to keep them in an isolated directory, that’s what Bundler’s standard mode and Go modules do. There’s just some lookup logic that loads the right things from the shared directories.

                            1. 2

                              The point is that any runtime dynamic linking system has to think about this stuff in ways that compile-time static linking can just ignore by downloading into a local subdirectory.

                              Isolated runtime directories like a Python venv or a node_modules also don’t come for free – they proliferate multiple copies of dependencies throughout different locations on the filesystem, and make things like upgrades (especially security issues) more difficult, since now you have go track down every single copy of the outdated library.

          2. 8

            It might be possible to have this issue in other languages and ecosystems, but most of them avoid them because their communities have developed good conventions and best practices around both package versioning (and the contracts around versioning) and dependency version bound specification, whereas a lot of the Python packages predate there being much community consensus in this area. In practice I see very little of it comparatively in say, npm and Cargo. Though obviously this is just anecdotal.

            1. 1

              Pretty sure it’s not possible to have this issue in either of your two examples; npm because all dependencies have their transitive dependencies isolated from other dependencies’ transitive dependencies, and it just creates a whole tree of dependencies in the filesystem (which comes with its own problems), and Cargo because, as @mxey pointed out (after your comment), dependencies are statically linked into their dependents, which are statically linked into their dependents, all the way up.

              This has been a big problem in the Haskell ecosystem (known as Cabal hell), although it’s been heavily attacked with Stack (a package set that are known to all work together), and cabal v2-* commands (which builds all the dependencies for a given project in an isolated directory), but I don’t think that solves it completely transitively.

              1. 2

                @mxey pointed out (after your comment), dependencies are statically linked into their dependents, which are statically linked into their dependents, all the way up.

                That’s not true for Go. Everything that is part of the same build has their requirements combined, across modules. See for the process. In summary: if 2 modules are part of the same build and they require the same dependency, then the higher version of the 2 specified will be used (different major versions are handled as different modules). My point was only that it’s completely reproducible irrelevant of the system state or the state of the world outside the go.mod files.

                1. 1

                  Ah, I misunderstood your comment and misinterpreted @ubernostrum’s response to your comment. Thanks for clarifying. Apologies for my lack of clarity and misleading wording.

              2. 1

                To be clear, I’m not talking about transitive dependencies being shared inappropriately, but the much simpler and higher level problem of just having inappropriate dependency versioning, which causes the packages to pick up versions with breaking API changes.

                1. 1

                  Ah, I reread your original comment:

                  For example, having lockfiles are great, but they don’t help you if the packages themselves specify poor/incorrect package version bounds when you come to refresh your lockfiles (and this is something I’ve been bitten by personally).

                  Are you talking about transitive dependencies being upgraded with a major version despite the parent dependency only being upgraded by a minor or patch version because of the parent dependency being too loose in their version constraints? Are you saying this is much more endemic problem in the Python community?

                  1. 2

                    Well, it fits into one of two problem areas:

                    • As you say, incorrect version specification in dependencias allowing major version upgrades when not appropriate - this is something I rarely if ever see outside Python.

                    • A failure of common understanding of the contracts around versioning, either by a maintainer who doesn’t make semver-like guarantees but downstream consumers who assume they do, or the accidental release of breaking changes when not intended. This happens everywhere but I (anecdotally) encounter it more often with Python packages.

              3. 1

                npm because all dependencies have their transitive dependencies isolated from other dependencies’ transitive dependencies

                npm has had dedupe and yarn has had --flat for years now.

                Go handles it by enforcing that you can have multiples of major versions but not minor or patch (so having both dep v1.2.3 and v2.3.4 is okay, but you can’t have both v1.2.3 and v1.4.5).

                1. 1

                  npm has had dedupe and yarn has had --flat for years now.

                  I was unaware of that, but is it required or optional? If it’s optional, then by default, you wouldn’t have this problem of sharing possibly conflicting (for any reason) dependencies, right? What were the reasons for adding this?

      3. 11

        I have mixed feelings about Poetry. I started using it when I didn’t know any better and it seemed like the way to go, but as time goes on it’s becoming evident that it’s probably not even necessary for my use case and I’m better served with a vanilla pip workflow. I’m especially bothered by the slow update and install times, how it doesn’t always do what I expected (just update a single package), and how it seems to be so very over-engineered. Anthony Sottile of anthonywritescode (great channel, check it out) has made a video highlighting why he will never use Poetry that’s also worth a watch.

        1. 5

          If you have an article that summarizes the Poetry flaws I’d appreciate it (I’m not a big video person). I’ll defer to your opinion here since I’m not as active in Python development as I was a few years ago, so I haven’t worked with a lot of the newer tooling extensively.

          But I think that further complicates the whole Python dependency management story if Poetry is heavily flawed. I do remember using it a few years back and it was weirdly tricky to get working, but I had hoped those issues were fixed. Disappointing to hear Poetry is not holding up to expectations, though I will say proper dependency management is a gritty hard problem, especially retrofitting it into an ecosystem that has not had it before.

          1. 15

            Sure, here’s what he laid out in the video from his point of view:

            • he ran into 3 bugs in the first 5 minutes when using it for the first time back in 2020, which didn’t bode well
            • it pulls in quite a few dependencies (45 at the time of writing this, which includes transitive dependencies)
              • create virtual environment
              • pip install poetry
              • pip freeze --all | wc -l
            • it by default adds dependencies to your project that automatically would result in updates up to either a major or minor version bump, depending on the initial version
              • for example python = "^3.8", which is equivalent to >= 3.8, <4
              • this causes conflicts with dependencies of libraries that are often updated and with those that aren’t
                • he mentions requests specifically
            • pip already has a dependency resolver and a way to freeze requirements and their very specific versions
              • i.e. use == and not use caret or tilde versioning
              • he also shouts out ‘pip-tools’ here, which I haven’t used myself for the sake of keeping things simple
            • the maintainers of Poetry have done something weird with how they wanted to deprecate an installer, which has eroded trust (for him)
              • they essentially introduced a 5% chance that any CI job that used (their old way of installing Poetry) would fail to get people to move away from using that script and if you weren’t in CI then the script would just fail
              • this is terrible because it introduces unnecessary flakiness in CI systems and does not give people time to actually migrate away in their own time, but rather forces it upon them
            1. 6

              I have used pip-tools and it is my favorite way of doing dependency management in Python, but it’s also part of the problem because I have a solution for me, so it doesn’t matter that the core tools are user hostile. The Python core team should really be taking ownership of this problem instead of letting it dissolve into a million different little solutions.

            2. 5

              the maintainers of Poetry have done something weird with how they wanted to deprecate an installer, which has eroded trust (for him)

              I don’t wish to ascribe malice to people, but it comes off as contemptuous of users.

              Infrastructure should be as invisible as possible. Poetry deprecating something is Poetry’s problem. Pushing it on all users presumes that they care, can act on it, and have time/money/energy to deal with it. Ridiculous.

              1. 1

                Absolutely, very unprofessional. Is the tool deprecated? Just drop the damn tool, don’t bring down my CI! You don’t want future versions? Don’t release any!

        2. 1

          I wanted to just settle on Poetry. I was willing to overlook so many flaws.

          I have simply never gotten it to work on Windows. Oh well.

      4. 5

        Poetry is here though and is ready to use. There are good reasons to not make things included and frozen in upstream distribution. For example rubygems is separate from ruby. Cargo is separate from the rust compiler. The Python project itself doesn’t have to do anything here. It would be nice if they said: this is the blessed solution, but it doesn’t stop anyone now.

        1. 9

          Another commenter posted about the issues with Poetry, which I take as it not being quite ready to use everywhere. I think not having a blessed solution is a big mistake, and one that the JS ecosystem is also making (it’s now npm, yarn, and some other thing) — it complicates things for no discernible reason to the end user.

          While Cargo and rubygems may be separate from the compiler/interpreter, they are also closely linked and developed in sync (at least I know this is the case for Cargo). One of the best decisions the Rust team made was realizing that a language was its ecosystem, and investing heavily in the tooling that was best in class. Without a blessed solution from the Python team I feel as though the dependency management situation will continue as-is.

          1. 4

            There was a time in the beforefore, when we didn’t have bundler, and ruby dependency management was kind of brutal as well. I guess there is still hope for python if they decide to adopt something as a first-class citizen and take on these problems with an “official” answer.

      5. 2

        I tried to add advice about dependency and packaging tooling to my code style guide for Python. My best attempt exploded the size of the style guide by 2x the word count, so I abandoned the effort. I recently wrote about this here:

        I’d really like to understand Rust and Cargo a little better, but I’m not a Rust programmer at the moment. Any recommendations to read about the cargo and crate architecture?

    11. 11

      As this post is counterposing REPL-driven development to Python/Ruby, I can only conclude that the author has not done a significant amount of work in Ruby.

      1. Automatic code-reloading has been a feature of Ruby projects for ages
      2. Ruby REPLs such as Pry have sophisticated source analysis and editing features

      No, it’s not quite at the level of Smalltalk/Lisp because you aren’t editing the primary artifact. Code changes have to be saved to the filesystem to be permanent. However, I think this is in many ways a positive tradeoff because VM-based languages are quite difficult to work with compared to anything represented as source files.

      One of the most common things I do when developing software is drop example { binding.pry } into my spec file, then execute it to open a REPL within my test environment. I have a constant feedback loop between project source, spec files, and REPL as I develop. This is pretty close to what the author is talking about.

      1. 10

        Define a datatype. I mean a class, a struct, a record type–whatever user-defined type your favorite language supports. Make some instances of it. Write some functions (or methods, or procedures, or whatever) to operate on them.

        Now change the definition of the type. What happens?

        Does your language runtime notice that the definition of the type has changed?

        If the answer is “yes,” then you’re probably using a Lisp or Smalltalk system.

        Yeah, this person has obviously never used Ruby. Or Erlang. CL fans like to talk about their repl as the pinnacle of live development (with the occasional nod to Smalltalk as a fallen comrade worthy of respect) but Erlang’s live code loading can do things which CL programmers haven’t dreamed of.

        The reason you don’t see repl-based development done in Ruby is cultural, not technical. (which honestly makes it even more strange, but that’s how it is)

        Also, they don’t seem to understand the difference between the condition system from CL and the repl. The repl makes the condition system more useful, but not having a condition system and not having a repl are completely different things. AFAICT they are attempting to redefine “a proper repl” as “a repl and a condition system” but like… just… no. A repl is a repl and a condition system is a condition system; we don’t need more people muddying the waters. Say what you mean.

      2. 2

        Out of curiosity, what is the ruby equivalent to common lisp’s UPDATE-INSTANCE-FOR-REDEFINED-CLASS?

        1. 1

          I don’t believe there is a built-in, but ruby has the tools to migrate data in instances of class A to data that fits class A’.

          You can fetch all instances using ObjectSpace and re-assign instance variables.

          class A
            def foo
              @foo = "foo"
          a =
 # => "foo"
          b =
          # reopen the class
          class A
            def foo
              @bar = 'bar'
 # => 'bar'
 # => 'bar'
          a.instance_eval { @foo } # => 'foo'
          b.instance_eval { @foo } # => nil
          ObjectSpace.each_object(A) { |a| a.remove_instance_variable(:@foo) if a.instance_variable_defined?(:@foo) }
          a.instance_eval { @foo } # => nil
        2. 1

          Changes to a class object don’t flow into instances of the class automatically. This also works both ways: you can add functionality to an instance that the class doesn’t know about.

          In practice this isn’t much of a hardship because reinitializing an instance is easy.

          1. 1

            But it does, though. The existing instances of A both got the new definition of #foo. Why should a new method definition change/add/remove instance variables on existing instances? The instance variables have nothing to do with the class objects, they’re specific to instances only.

            1. 1

              You’re right, my mental model of this was wrong. Changes of implementation do flow into existing instances. Metaprogramming might interfere with this if code is being generated on the instance at runtime, but for the general case this works.

              1. 1

                It’s all at runtime. Metaprogramming in Ruby is at the same (conceptual) ‘layer’ as any other programming.

                irb(main):001:0> class A
                irb(main):002:1>   def foo
                irb(main):003:2>     @foo = "foo"
                irb(main):004:2>   end
                irb(main):005:1> end
                => :foo
                irb(main):006:0> a =
                => #<A:0x000000012d848798>
                => "foo"
                irb(main):008:0> b =
                => #<A:0x000000012d833848>
                irb(main):009:0> A.define_method(:foo) { @bar = 'bar' }
                => :foo
                => "bar"
                => "bar"
                irb(main):012:0> a.instance_eval { @foo }
                => "foo"
                irb(main):013:0> b.instance_eval { @foo }
                => nil
                irb(main):014:0> a.instance_variable_get :@foo
                => "foo"
                irb(main):015:0> b.instance_variable_get :@foo
                => nil
                irb(main):016:0> a.class
                => A
                irb(main):017:0> a.class.instance_eval do
                irb(main):018:1*   def a_class_method
                irb(main):019:2>     :a_class_method
                irb(main):020:2>   end
                irb(main):021:1> end
                => :a_class_method
                irb(main):022:0> A.a_class_method
                => :a_class_method
                irb(main):023:0> a.class.class_eval do
                irb(main):024:1*   def bar
                irb(main):025:2>     :bar
                irb(main):026:2>   end
                irb(main):027:1> end
                => :bar
                => :bar
                => :bar
                irb(main):030:0> a.baz
                Traceback (most recent call last):
                        4: from /usr/bin/irb:23:in `<main>'
                        3: from /usr/bin/irb:23:in `load'
                        2: from /Library/Ruby/Gems/2.6.0/gems/irb-1.0.0/exe/irb:11:in `<top (required)>'
                        1: from (irb):30
                NoMethodError (undefined method `baz' for #<A:0x000000012d848798 @foo="foo", @bar="bar">)
                Did you mean?  bar
                irb(main):031:0> b.class.class_eval do
                irb(main):032:1*   def baz
                irb(main):033:2>     :baz
                irb(main):034:2>   end
                irb(main):035:1> end
                => :baz
                irb(main):036:0> a.baz
                => :baz
    12. 2

      Interesting that it seems to work better on Firefox than Tor Browser, which is essentially Firefox.

    13. 1

      I had started a command-as-escape-when-pressed-alone remapping years ago when Apple came out with their stupid touch bar laptops without a physical escape key which an old employer provided for me. It ended up working so well for me that I quickly started used it on my personal machine as well, which doesn’t have a touch bar.

      When I started working with a new client who provided their own locked down machine, Elements stopped working (if it ever did on that machine, I think an update actually broke it).

      Commandeer, which hooks into Apple’s Quartz Events framework instead of reading directly using a kernel extension, seems to work fine on my locked down machine.

      1. 2

        About to use a Mac so definitely appreciate this!

    14. 1

      I have a stupid little post-checkout script I wrote a few years back that copies all the migrations you need to rollback to a temporary directory and then printed a message with the command to run to rollback those migrations.

      I don’t use it; I only wrote it to practice my Haskell at the time.

    15. 3

      But if you don’t find HJKL intuitive or ergonomic, why are you using vim? Why not use some other editor that doesn’t have that navigation baked in at such a deep level?

      1. 28

        Vim is so, so, so much more than the keys you use to move by character.

      2. 8

        I don’t think it’s particularly baked in, four noremap commands in a .vimrc should replace all usage. (I say that, but probably a vim expert will point out they also need to be remapped in some odd half-mode or something.) And if the author doesn’t care for it, yeah, they should tweak or replace their editor, there’s no value in standing on tradition here.

      3. 8

        I’ve used vim for over 25 years and have never used hjkl navigation. I’ve always used the arrow keys. This has never hindered my usage of vim and the only time I notice it is those rare occasions when vim is set up really badly by default, (looking at you FreeBSD). Vim is not just hjkl navigation and has a lot of features that a lot of other editors don’t have, but modal editing is why I’ve never looked at other editors.

        1. 1

          Not using hjkl doesn’t hinder your usage of Vim, but I do think it’s beneficial over using the arrow keys. After it’s in my muscle memory (which didn’t take long), whenever I found myself in insert mode and just needing to do a quick edit on the line below, for example — let’s say I spot a small typo while working on the line above — I found I was getting irritated at the delay I was feeling from having to navigate my hands to the arrow keys corner. I’m on a laptop keyboard, and I can only imagine how much worse it would’ve been on a larger desktop keyboard.

    16. 15

      I think I agree with the first person who wrote him a letter. There is a difference between finding more novel and varied examples and picking examples designed to goad your readers.

      Please in the future, remember that we, the book buyers, are looking for information about using PL/SQL. I am as tired of the emp and dept tables as you are, but less distracting examples would have been more appropriate.

      Everyone has a political view and sometimes that arises legitimately in technology but I think it’s just basic self-control to express your political view only where it really might help something.

      1. 21

        The dude’s point is that we all have a political perspective, and we’re expressing it, either explicitly or implicitly. He chose to express his explicitly through the examples in his textbook.

        If you write a database text and fill it with department / employee type examples, shopping examples, and so forth, then you are implicitly promoting a capitalist world view, the same world view that does not bat an eye when using degrading terms like “human resources”. At least here in the US, this sort of thing goes unquestioned, because of the dominant ideology.

        1. 5

          Yes, it’s implicit, it’s unquestioned and nobody bats an eye - and that’s why it makes for better examples.

          Examples require the use of social territory. That territory can be either unquestioned good or questioned territory. When choosing examples in questioned territory, you engage in active cultural participation; when choosing examples in unquestioned territory, you engage in passive cultural participation. Examples should engage in passive participation, because that way they are relatable to the greatest number of readers.

          (You can also use unquestioned bad territory, such as defining a database schema to count Jews in the Holocaust for the Nazis, but then nobody will buy your book.)

          1. 9

            I don’t see why “nobody bats an eye” is a desirable quality for examples or why “active cultural participation” is a bad thing.

            It’s not at all clear to me that the examples given are not relatable or that “relatable to the greatest number of readers” should even be a core value. Perhaps provocative examples engage readers more and cause them to think about the examples more.

            1. 5

              Would be curious how you’d feel if it were something sorting countries by iq or something.

              Would you be happy to be engaged, or be distracted by a thinking about testing methodology and things like that?

              1. 3

                I’d have to see it in context to find out how I’d react. IQ is strongly related to class and similarity to the people who devised the test, and such a table might be part of a demonstration of that.

                Certainly if an example just seemed pointlessly offensive I would think less of the author and maybe choose a different textbook.

                But I think equating a hypothetical very racist example with some examples that are a bit left of centre in the USA is unfair.

                1. 3

                  A substantial amount of political dispute in the English speaking world is precisely about what speech counts as racist and therefore legitimately stigmatizable. Using data that implies that cognitive capacity is meaningfully different between different countries of the world in a programming example constitutes a political assertion that this idea is not stigmatizable; in the same way that the article’s example about a war criminal database constitutes a political assertion about how people should see Henry Kissinger.

          2. 6

            But now you’ve thought about it, so it has become active participation. From now on you are obliged to make sure your examples completely apolitical.

            Consider engineers have a code of ethics,

            If your work includes producing examples they should “serve humanity”. I cannot conscientiously make examples that promote capitalism, but giving examples that might make people think about world affairs would be okay.

          3. 4

            Yes, it’s implicit, it’s unquestioned and nobody bats an eye - and that’s why it makes for better examples.

            That assumes a lot from the readership. For a mundane, apolitical example, I submit children to this discussion. For most my childhood due to various reasons, I only had access to a Pentium. It didn’t have a network connection, and I eventually installed Linux on it. Because Linux made it so easy to code, I would try to check out books from the library and learn how to write code, but all the examples were completely unrelatable to me as a pre-teen. Employee this, business that, I realized even at the time that the examples were meant to be highly relatable to practitioners, but I honestly found math much more interesting than these soulless books because I was unable to relate to them in any way. That was one of the big reasons I started out coding by trying to write games; game programming books felt much more relatable to me as a kid who read a lot of books and played video games than these soulless books about employee hierarchies and recipes.

            Also, it’s important to keep in mind that the conditions that make something unpolitical are pretty restricted in context. Someone growing up in a developing country or a country with a very different economic ideology will probably find these staid business examples just as unrelatable as children. International editions of textbooks frequently do change examples for exactly this reason.

            1. 1

              I would try to check out books from the library and learn how to write code, but all the examples were completely unrelatable to me as a pre-teen. Employee this, business that, I realized even at the time that the examples were meant to be highly relatable to practitioners, but I honestly found math much more interesting than these soulless books because I was unable to relate to them in any way.

              I also started learning at a young age, and I find this attitude so alien.

      2. 5

        Everyone has a political view and sometimes that arises legitimately in technology but I think it’s just basic self-control to express your political view only where it really might help something.

        I am totally with you on this, and do my best to keep my political perspectives away from the technology work I do as much as I can. I have worked on projects with ethical/political considerations (whether someone might consider a few of these projects ethical depends on their personal political leanings.) Definitely a touchy subject.

        That being said, I have a really hard time empathizing with the readers who wrote in to complain that the examples are too distracting. I believe a database book aught to have concrete examples while teaching the abstract concepts (e.g. it’s a book about writing databases in general, not “how to keep track of war criminals”). My own personal reaction to the examples talked about are “ok, whether I agree with the premise or not, these examples have interesting abstract concepts that they’re illustrating.” There are lots of systems that exist in this world whose existence I fundamentally disagree with, but where I’d also love to pop the hood and figure out how they work!

        In fact, as I sat here thinking about this, I started wondering if, for me, this style of examples might actually help cement specific concepts with easy mental look-up keys; I can imagine coming to a database design problem and thinking “oh, this is like the Kissinger problem.”

    17. 6

      Why compare with 3G? I can only assume that is due to availability in developing nations. When I search for ‘1996 worldwide internet coverage’ the very first link for me claims that at that time only 20 million Americans had internet access. So it seems that if we’re intent on using 3G as a comparison, then to be fair we should compare that with the probable equivalent in 1996 – no internet access at all.

      Look, I hate modern web bloat too, but this is cherry picking.

      1. 1

        100% agree. I don’t disagree with the general sentiment of the article, but the example is extremely contrived.

      2. 1

        Not only that, but this movie is presumably mostly targeted at people with money, not people without.

      3. 10

        I’m not sure why you are trying to contort the meaning of the original article into some “pure functional programming bad”, which is very obviously not the point of the article. In fact, you fall victim to the exact pattern the article criticizes.

        I recommend some self-reflection.

        1. 1

          The original article talks about elitist fucktards in the software industry. I expand on that by stating that programming languages are also elitist and part of the same problem. “Pure” functional programming along with OO is theological in nature, faith driven, derives its elitism from childish notions of “purity” and has no evidence for all its claims.

          1. 1

            What kind of evidence are you exactly looking for?

            1. 1

              OO and FP were responses to the so-called software crisis of the 70s. I believe the claims were that using these “completely pure” as opposed to mixed techniques would

              1. Deliver faster software
              2. Deliver software fastly
              3. Increase software durability, safety, maintainability above and much beyond procedural programming
              4. Increase programmer productivity
              5. Make concurrent programs easy

              So far all I see is vague opinions on 4, nonsense and marketing slogans. AFAIK generic programming, seen in C++/Ada delivers some evidence on some of these claims.

              1. 1

                AFAIK generic programming, seen in C++/Ada delivers some evidence on some of these claims.


                1. 1

                  If I remember correctly Blitz++ uses templates to deliver faster code in some linear algebra stuff as compared to other solutions done in C or something. Generic programming also increases code reuse of algorithms. This paper by stepanov is a good read on the topic.

                  1. 1

                    Which particular claim (out of the 5 items listed above) does this paper provide evidence for?

                    Here’s the paper’s abstract:

                    Abstract. Generic programming depends on the decomposition of programs into components which may be developed separately and combined arbitrarily, subject only to well-defined interfaces. Among the interfaces of interest, indeed the most pervasively and unconsciously used, are the fundamental operators common to all C++ built-in types, as extended to user-defined types, e.g. copy constructors, assignment, and equality. We investigate the relations which must hold among these operators to preserve consistency with their semantics for the built-in types and with the expectations of programmers. We can produce an axiomatization of these operators which yields the required consistency with built-in types, matches the intuitive expectations of programmers, and also reflects our underlying mathematical expectations.

                    Nowhere in the abstract, or its conclusions, do I see a reference to (much less a discussion of) of any of the five claims above?

                    Also, if by “deliver faster software” you mean performant programs, then we have diverged far off from the original topic of FP purity being “elitism from childish notions” (your belief, for which there is no empirical evidence whatsoever either) - for which you wanted, if I understand you correctly, empirical evidence (the kind FP programmers don’t bother producing, while they are busy producing software).

                    If you wait for experimentally concluded empirical evidence in software technology before allowing yourself to actually try out new technology or methods so as to arrive at an experiential knowledge, there will be little progress towards anything better and only stagnancy shall remain as ongoing modus operandi.

      4. 1

        Compare Haskell vs Ocaml. One is actually used in the industry and the other is used as a dependency for pandoc.

        Have you got figures to support that Haskell (the pandoc dependency) is used less than OCaml in industry? I’d be surprised if that’s the case.

    18. 13

      It was his project. Why shouldn’t he be on the board?

      1. 36

        I don’t know, that’s sort of like me saying “it was his company, why shouldn’t he be able to run it into the ground?”

        In both cases, the answer is the same I think: he’s not the only one on the ship, so it’d be pretty awful of him to sink it

      2. 12

        The argument was that he supported Epstein.

        Some people argued his statement was poorly worded, some argued that it reflected prior statements.

        Honestly, I dislike him in general for other reasons, although at least he isn’t ESR.

        Personally I feel the better question is:

        Why was he kicked out if it’s appropriate for him to return? Or the reverse, if it’s considered appropriate for him to return, why was he kicked out?

        e.g. did you make a real choice when he was kicked off or was it purely a political move

        1. 24

          The argument was that he supported Epstein.

          I think you either misunderstood what was being said at the time, or you’re extrapolating in dangerous ways what RMS posted on the MIT mailing list. Could you please dig up some links that support your statement?

        2. 10

          Possibly more problematic than his support for Epstein (in terms of relevance to his board membership): he’s actively transmisogynistic, anti-queer, and apparently awful to be around most of the time if you’re not a cis dude. So for anyone interested in a more forward-thinking and diverse FSF (i.e. one that is not actively hostile to possible members/supporters/contributors who belong to certain demographics), having someone like him on the panel would be a bit concerning.

          1. 10

            [..] his support for Epstein

            Since parent hasn’t substantiated this claim, could you please do it? I feel like it represents a gross mischaracterization of what RMS posted on the MIT mailing list. If you have evidence to the opposite I’d like to see that.

            1. 7

              Accusing me of defamation (i.e. of making spurious false statements) and calling for the site owners to nuke my account or force me to dox myself 1. implies my comments were false right off the bat and 2. doesn’t really make me want to engage with you, since it comes off like you’re trying to intimidate me. Further, it makes me wonder what you’d even do with my real-life identity if you knew it, making you come off a bit creepy and hostile. So, given the main reason I maintain pseudo-anonymity is to avoid being targeted by creepy & hostile weirdos on the internet, as it concerns identifying myself: respectfully, no thanks! Although if you’re determined/creepy enough, I shouldn’t be too hard to unmask

              Presumably you’re a hacker (in the original sense of the word – i.e. this is a compliment, not an accusation), and so presumably you have fairly well-honed Google-fu, so I’m honestly not sure why you and the parent are having trouble here. Fruitful search queries to get you started include “richard stallman harassment of women” and “richard stallman comments about women” and “richard stallman sexism”.

              Anyway, virtually all of the results are anecdotal (except for the now-infamous comments Stallman made on the mailing list), which some may take issue with. I personally believe victims, and I think when such anecdotes multiply over the course of many decades as they have in Stallman’s case, they tend to suggest a pattern of behavior.

              You used an interesting argument in another comment about how labels are dangerous because they don’t take into account who a person is now and how they’ve grown since. Rather they focus on a snapshot of the person as they were (perhaps making an offhanded and thoughtless comment). I think there is something to be said for this position, but my experience has been that people are generally willing to take growth into account if growth is shown. It really does not take much other than showing some sincerity & good faith – apologies go a long way, as do comments affirming queer/trans folks, or “my thoughtless comment wasn’t intended to dehumanize xyz, you’re right, I could have said that better”. Unfortunately we haven’t seen this at all from Stallman.

              1. 7

                If your entire premise here is that people aren’t allowed to discuss something unless they risk physically violent reprisal for their comments, and it certainly seems like that’s what you’re pushing, then:

                1. No.
                2. It suggests strongly that you don’t have, or don’t care if you have, facts and reason on your side, because the argument can always be “won” through violence or threat of the same. Making it a literal ad hominem, because the counterargument is against the person. A world where might makes right is not a world I particularly want to live in, and I think you probably don’t either – there’s always someone bigger/stronger/meaner who’ll be along eventually to teach you why.
                3. Still no.

                If you’re still here at this point: strongly suggest you take a long, long break from the internet.

                1. 0

                  It is cowardly to attack another person from an anonymous account.

                  You want to attack an idea or organization, fine. But it is cowardly and dishonorable to throw stones at someone from an anonymous account. Always has been and always will be.

              2. 4

                Even if that could get you hurt? No, ESPECIALLY if that could get you hurt.

                You would really do well to consider how radically different life is for people who aren’t cis white men.

                1. 0

                  That’s right because I’ve never had guns pointed at my head or the shit kicked out of me by an angry mob standing up for what is right. I’m not talking about figuratively online.

                  Here’s a great video on courage:

          2. 7

            It’s often unsafe for queer people to use their real name online. Instituting a policy like that can simply remove whole swathes of minorities from discussions for that reason. If you think someone’s rhetoric amounts to “defamation” and don’t like that they’re anonymous, just accord it the attention you believe it deserves and move on.

            1. 0

              Fair enough. I just think there should be no place for lazy anonymous content. If you want to post anonymously, fine, but put a shred of effort into it before you write. There should be an extremely high bar of data backing if you post anonymous stuff. Otherwise this site is supporting defamation.

      3. 9

        Do you have a source on transmisogyny/anti-queer? All I could find was, which is pretty tame (he’s just being stupid about grammar, which fits the neuroatypical M.O.)

      4. 6

        he’s actively transmisogynistic, anti-queer

        What has he said or done that makes him anti-queer and transphobic? (genuine question and not a challenge btw, because I can’t remember seeing this ever being brought up before.)

        1. 6

          I am struggling to see it; I am even pleasantly surprised:

          A proposed California bill would stop the state from doing business with companies that discriminate against transgender employees.

          I think it is a step in the right direction.

          I think his opinions on pronouns are perhaps off-the-mark, but not harmful (and oddly plural-friendly).

          1. 8

            There was an incident a few years ago where a transgender FSF employee was being harassed by a coworker for being trans. The employee brought it up to Stallman, who responded by terminating the trans employee.

            The incident is discussed in this thread

            In various places on his personal website he announces that he won’t use “they/them” pronouns for individuals and ridicules usage of singular “they/them”, despite the fact that “they/them” pronouns are some people’s chosen pronouns.

            So while he posts stuff stating approval/support for queer and transgender folks (and that’s great), it is clear from other writing of his and also from his treatment of transgender folks that his support isn’t rooted in actually talking to people about this stuff.

            1. 5

              Who knows what happened with that foring, or even how Stallman was involved. Maybe it was really bad. Maybe it wasn’t. Unless there’s a pattern of things it seems a bit much to attach these sort of descriptions like anti-queer.

              And I don’t think that having a different opinion on the future evolution of the English language to be more inclusive makes one “actively transmisogynistic, anti-queer”. I read his pronoun article before; you can dislike his “language innovation” but he seems to be doing it for the right reasons. As you said, you actively supports transgender people, which fits my general impression of him as fairly progressive (some issues with personal behaviour notwithstanding) so I was surprised by your description. He basically agrees with you: language should be inclusive, there is just a disagreement on how this can best be done. If this is the best you can come up with then, to be completely honest, is not a good look for you here, because what it looks like is the casual hurling of slurs over a fairly minor disagreement. It’s kinda toxic to be honest.

              As I have described at length elsewhere in this thread, I really don’t like Stallman and haven’t for a very long time. But please, let’s not turn him in to a devil he’s not.

              1. 2

                I’m not sure that calling Stallman “anti-trans” is correct either. To me, he seems more like your generally older, left-of-center out of touch dudes who haunt the American internet. He’s not kept up on the social changes in his sphere.

                The real question is, should a person like that be in a leadership position of an advocacy group? That’s for the FSF leadership and membership to decide.

                1. 3

                  To me, he seems more like your generally older, left-of-center out of touch dudes who haunt the American internet. He’s not kept up on the social changes in his sphere.

                  This sounds about right; combined with perhaps a rather large dose of stubbornness. In Dutch we have a rather nice word for this: “eigenwijs”, literally translated it’s “own wisdom”. It’s not exactly “stubbornness” but more “can only convinced by their own wisdom”. There isn’t really a word in English for this AFAIK.

                  A lot of people are so quick to take everything in bad faith nowadays. It’s okay to be a bit older, “out of touch”, be pedantic, and have some eclectic opinions you post on your website that 6 people read. That doesn’t make you some sort of horrible person.

                  The real question is, should a person like that be in a leadership position of an advocacy group?

                  No, of course not.

                  1. 2

                    In Dutch we have a rather nice word for this: “eigenwijs”, literally translated it’s “own wisdom”. It’s not exactly “stubbornness” but more “can only convinced by their own wisdom”. There isn’t really a word in English for this AFAIK.

                    Swedish has “envis” but it’s much more connected to being stubborn. Does Dutch have a word that’s more corresponding to “stubborn”?

                    1. 2

                      I’d use “koppig”; which translates to “headish” and probably has the same root as the English “headstrong” (and/or “pigheaded”, since “kop” is, traditionally anyway, only used to refer to the head of an animal).

                      Eigenwijs does imply some degree of stubbornness, but it’s not exactly the same.

                      1. 2

                        OK, Swedish has “tjurskallig” (bull headed) in similar context. Almost willfully stubborn.

                        Swedish has more Dutch loanwords than you might expect, and of course both are Germanic languages.

                        This is getting way off-topic, but thanks for taking the time!

            2. 4

              In various places on his personal website he announces that he won’t use “they/them” pronouns for individuals and ridicules usage of singular “they/them”, despite the fact that “they/them” pronouns are some people’s chosen pronouns.

              This qualifies as “actively transmisogynistic”? I think your definitions are different than mine, probably to a severe degree. He even says he’s totally fine with using they/them for plural people, and he says that he’ll call you whatever you like even if it makes him personally mad!

              Dunno about the FSF firing thing, looking at news articles makes it look not exactly cut and dry. Rowe seems to be on good terms with Stallman now, perhaps it was a misunderstanding of some sort? Still seems absolutely unnecessary to call Stallman these horrible things. Call him out for making people uncomfortable with his “friendship cards” or whatever, sure, but come on.

              1. 4

                So, I interpreted his comments in that post and elsewhere as stating that he wouldn’t comply with they/them pronouns. But regardless, ridiculing someone’s choice of pronouns is actively anti-queer. Saying “I’ll respect your pronouns but I think they’re silly” (which is the most charitable interpretation of what he’s written) is actively hostile in my book.

                RE: the firing, I err on the side of believing victims. And Rowe was a friend of the person who was fired, not the person who was actually fired, so it’s immaterial what her current relationship is with Stallman.

                1. 3

                  Yes, and Rowe was the complaintant (spelling?) in that situation, right? I couldn’t see any statement or anything from the fired employee, only Rowe’s. “I err on the side of believing victims” is all well and good, but it doesn’t look like the victim said anything? (and is also a hilarious way to imply that I don’t believe victims, nice one!).

                  You can read his statements regarding pronouns however you like, I think he’s being a dickhead about it but I don’t think he’s being actively transmisogynistic. Or, to take a page from your book, maybe you’re being ableist to a clearly neurodivergent figure? Probably not, but that’s how I’m going to read what you’re saying now.

                  1. 1

                    Has Stallman ever identified himself as neurodivergent? It’s not a neutral term. I’d hesitate to apply it to someone against their express wishes.

                    In the previous hellthread, @mempko states that Stallman has described himself as “borderline autistic”.


                    Based on a comment in the previous hellthread, someone states that Stallman has described himself as “borderline autistic”.

      5. 9

        this is all that needed to be said. people are out here parsing his statements with a magnifying glass when he’s clearly been a mysogynist, he’s been anti-trans and anti-queer for a very long time. If we want a more inclusive community it starts at the top

        1. 2

          I like how you have a non-anon account. Then we can have a conversation.

          You call him “anti-trans” and “anti-queer”. Can you back that up with data? Does he ever specifically give himself those labels or are you giving him those labels? If you are giving him those labels, based upon what data? What percentage of software and writings by RMS could be labelled that? Does 50% of his writing focus on those categories? 10%? 1%? .1%? 0.01%? 0.00001%?

          I for one read a lot of his code and writings, and can’t remember him ever talking about those issues so I would be very surprised if those were relevant labels at all to him.

          Also, growing up in Boston it was very common to use the terms “gay” and “fag” and “queer” in a derogatory sense early and often. It wasn’t until I dropped a “that’s gay” freshman year of college and a female hall mate from California (became a best friend) stormed off in disgust that I had any notion I was on the wrong side of that one. Could you have called 18 year old me “anti-gay”? Absolutely. But I just was ignorant, and eventually matured.

          I think labelling people is generally a bad idea. It would be like labelling a new garden “dead” before you even gave the seedlings a chance to grow.

  1. 7

    He had to leave due to a heated controversy that originated in a MIT mailing list. Details here:

    1. 23

      That’s not a particularly good source. The original article that led to his resignation is a better place to start reading:

      You can also skip all that and just go read the CSAIL mailing list exchange yourself first, found at the bottom of this Vice article:

      Finally, just a general disclaimer: Stallman didn’t resign just because of the article by Selam, but rather because of the wide range of news coverage that documented his past behavior. Selam’s article was really just a catalyst.

      1. 16

        Stallman didn’t resign just because of the article by Selam, but rather because of the wide range of news coverage that documented his past behavior.

        Or, rather, a bunch of slander, which is documented here.

        1. 19

          Truth is an absolute defense to slander, and the article you link must admit that the things it analyzes are all ultimately rooted in things that Stallman actually factually truthfully really said and did. Beyond that it’s just a matter of how the author of that article and the authors of other articles subjectively interpret the given facts, which is a matter of opinion and thus something slander explicitly cannot apply to. So you should probably stop referring to “slander” in this context.

          1. 1

            Reporting that someone “says that an enslaved child [implied to be in the general case] could, somehow, be “entirely willing”” when they actually say that a [particular] enslaved minor close to age of majority in one specific country (not a child) may have presented themselves as willing — i.e. acted as if they were willing, i.e. propositioned someone who would have no idea that they were a slave or a minor — is clear, unadulterated slander.

            That it’s rooted in something that Stallman said doesn’t change that; twisting someone’s words in such a disgusting way is as wrong a lie as making something up entirely from scratch.

            I find it sick that you can actually pretend that the claims made about what Stallman said could be characterised as “truth”. Truth is an absolute defence to slander, but there was plenty of untruth propagated about what Stallman actually said.

            So I will not stop referring to slander in this context (though I am not @ethoh).

      2. 7

        Just reading some of that first link. The best word used was harem - I mean how does somebody use that word in a serious way in a non-historical context? I always knew the guy was eccentric, but he really comes off as a piece of garbage.

        I hadn’t even heard about any of this (don’t really pay attention on that side of the fence), boy oh boy. Thanks for those links.

        1. 6

          I see the word harem used all the time (and sometimes use it myself) and don’t at all see how it’s usage would make somebody “a piece of garbage”, can you elaborate?

          1. 10

            Have you used it to suggest that economically disadvantaged women and children being actively trafficked by a convicted sex offender constitute a harem*? Because that’s the usage that (among other things) makes Stallman “come off as a piece of garbage.” Which, if we’re going to keep trying to rules-lawyer, is not the same thing as ‘making [him] a “piece of garbage”’.

            * If we’re being at all technical a harem is an architectural feature; we probably should retire the word when applied to anything else.

  2. 11

    You work on Void Linux, right? Can’t we say the same thing about Juan and Void? Clearly things aren’t always as simple as “it’s his project”.

    1. 6

      Touche. I’ll not be responding, but I appreciate the chuckle.

  3. 8

    Please read the Wikipedia article about him.

    1. 6

      None of which are criticisms of his work or even his working persona, but his personal persona.

      1. 21

        You can’t be a leader with half of your personality. While I agree that some things are in the realm of private, your personal blog and your public speeches aren’t. You can’t go and have spicy opinions on your personal blog all the time and then pretend that they do not matter when running your projects and finding your peers in your projects.

        People are particularly questioning his ability to lead GNU and the FSF in a new era.

        I also don’t know how 33 GNU developers signing a letter that Stallman can’t remain the head of the GNU project can be anything but criticism of his working persona.

  4. 8

    I guess that depends whether the project wants to be judged by the things RMS says about.. you know … fucking kids.. fucking corpses.. etc.

  • 25

    There’s a very real sense in which Ubuntu is a flaming rubbish fire of a desktop, but honestly it means I don’t have to deal with Mac OS X or Windows and that’s enough for me. I used Windows a great deal when I was younger, and I tried using OS X for five years after moving to the US with only the Macbooks that would fit in my suitcase; I really can’t stand using either one.

    I just like the way X11 and tiling window managers feel (i3 now, formerly dwm) and I like having a vaguely UNIX-like OS underneath. For better or worse, Ubuntu is able to drive my desktops and my ThinkPad and runs the applications I want – with Proton it even runs many Windows games. So, while it’s a rubbish fire with all of the problems the article describes, it’s my preferred rubbish fire for right now. I’m not sure the grass is really greener anywhere else.

    1. 7

      This comment got longer than I planned. TL;DR: Mac good, then Mac outrageously bad, now Mac good again.

      I got my first Mac in 2013, when MacBooks and MacOS were peaking. Within a few years, the steady decline of MacOS began, to my great disappointment. All the slowdowns and extremely blatant UI bugs made my $3k+ work MacBook Pro feel like a cheap piece of junk.

      When my 2013 MacBook Pro replaced my ThinkPad T61 (from 2007ish?), I remember being absolutely blown away that the MacOS lock screen rendered before I could even open the lid enough to type my password. Not a particularly spectacular benchmark, I know, but it illustrates how far Macs fell: just a few years later my work MacBook Pro would take 10-15 seconds to become responsive when waking up.

      And the bugs. My god, the bugs. I tried for a good 30 minutes to connect Apple Music to my bigger B&W speakers using shairport-sync. Never worked, even though my iPhone works fine. It did, however, give me lots of confusing feedback with checkmarks checking and unchecking themselves, spinners, and completely disrupting the rest of my system audio. Eventually I rebooted to end the pain.

      But I heard the new M1 Macs fixed everything, so I took a chance and got an M1 MacBook Air. If it still sucked, I was ready to return it and switch back to Linux after all this time.

      I have to say, it dramatically exceeded my expectations.

      My new M1 MacBook Air has that old snappy responsive feel I loved about my first MacBook Pro. Passes my lame open-the-lid-from-sleep test with flying colors. And connecting to my speakers works instantly and flawlessly—even allowing me to send only Apple Music to my big speakers, and keep using my desk speakers for the rest of the system.

      The M1 does literally everything better. I could probably come up with dozens more examples, but for whatever reason those two problems infuriated me the most.

      Anyway, I’m not trying to sell you or anyone else on Macs. I’m just ecstatic my preferred OS doesn’t suck anymore. I don’t know when you moved to the US, maybe your 5 years of MacOS happened smack in the middle of the dark days? Or maybe you just don’t like MacOS. Obviously, that’s your prerogative. Even though you call your setup a rubbish fire, I’m glad you have something that works for you!

      1. 12

        my lame open-the-lid-from-sleep test

        This isn’t lame, this is human usability.

        Story time: this morning I grabbed my Linux laptop running KDE Plasma for a few files off of it before I head in to work. (Also noticed my article got posted here, hey!) When I opened the lid:

        • black screen

        • “22:40 Sunday”

        • redraw

        • “07:04 Monday”

        And yeah, it pissed me off.

        Then I grabbed my Mac. When I opened the lid:

        • “07:06 Monday”
        1. 6

          I can’t fathom how people are willing to sacrifice so much freedom because the screen contents may be stale. Somehow it never hurts my productivity, if I open the lid, I know I am opening the lid. I won’t be in the flow when opening the lid, I will already know what time it is when I open it. Is it condescending of me to call it vanity?

          1. 10

            This is exactly the perspective that keeps non-technical users from using FOSS. Their concerns are relegated to “vanity” by most. What is “vanity” to you may be essential to others. So when those others ask why this behavior occurs and receive the above response about “vanity not freedom”, they just politely drop FOSS and move on.

            1. 4

              Hard agree. Also, I’ve wasted about ten seconds per day on this (~3-5 seconds * 2-3 lid events per day).

              I’ve been running Linux on this laptop since 2015.

              21,900 seconds, or 6 hours, of my life has been wasted on this “vanity” bug regarding KDE’s lock screen.

              Tiny amounts of performance can have huge amounts of waste when you have economies of scale like this, especially when it’s a daily-driven workstation used for multiple years. Think of the board games I could have played with my Mum, the meme videos I could have watched with my friends, and the snuggles I could have given my cat in that time. (Let alone the open source code I could have been writing.)

      2. 1

        I got my first Mac in 2013, when MacBooks and MacOS were peaking.

        Do you mean in quality (in your opinion) or popularity?

        1. 1

          This was some time ago so I don’t perfectly remember all of my reasoning. In quality most definitely, though in my opinion popularity played a huge role in software quality for developers.

          As a long time Linux user I wanted to continue using tools I was familiar with, which meant the shell, vim, package management, and the numerous command line tools I had grown accustomed to. Thus the quality, maturity, popularity, and package availability of Homebrew played a significant role in my evaluation.

          The late 2013 model I got was the first with a Haswell processor, and, if I recall correctly, NVMe SSD. I don’t remember why, but Haswell processors were supposed to have been a big leap over the previous generation. I think for battery life? And NVMe bandwidth was mind-blowing compared to SATA III.

          Lastly, it was still hard to beat my ThinkPad T61’s 1680x1050 display at the time, and I flat out refused to compromise on screen real estate, so the Retina display scaling to 1920x1200 was a big plus. I was in college at the time, so I didn’t usually have an external monitor. Whereas today I use my M1 MacBook Air with a 32” 2560x1440 monitor for serious work.

          In the technology adoption life cycle I’m squarely in the early majority, by no means an early adopter. I started pondering a switch to Macs after continued evidence from developers around me that OS X did everything I wanted it to do. The hardware leap of the late 2013 model sealed the deal for me and I ordered one as soon as the first OS X Mavericks patch release was announced.