1. 1

    Correct me if I’m wrong, but Mamba appears to require Conda during its installation process. Why is it the case given that Mamba is a re-implementation?

    By the way, Mamba’s integration with fish seems second-class, and it’s annoying that I must use conda activate foo instead of mamba activate foo.

    1. 4

      Mamba is a work-in-progress reimplementation. So it falls back to Conda for parts that haven’t been redone.

      There’s a just-Mamba version called micromamba that is a self-contained single-file executable, but e.g. it doesn’t yet support pip package installs from environment.yml and is mostly just intended for bootstrapping environments in CI or Docker, not as a day-to-day tool for development.

    1. 8

      My money is on SWAGGINZZZ :)

      1. 1

        this makes me wonder what the fastest possible ascension would be (without bones)

      1. 35

        Unlike say, VMs, containers have a minimal performance hit and overhead

        Ugh. I really hate it when people say things like that because it’s both wrong and a domain error:

        A container is a packaging format, a VM is an isolation mechanism. Containers can be deployed on VMs or they can be deployed with shared-kernel isolation mechanisms (such as FreeBSD Jails, Solaris Zones, Linux cgroups, namespaces seccomp-bpf and wishful thinking), , or with hybrids such as gVisor.

        Whether a VM or a shared-kernel system has more performance overhead is debatable. For example, FreeBSD Jails now support having per-jail copies of the entire network stack because using RSS in the hardware to route packets to a completely independent instance of the network stack gives better performance and scalability than sharing state owned by different jails in the same kernel data structures. Modern container-focused VM systems do aggressive page sharing and so have very little memory overhead and even without that the kernel is pretty tiny in comparison to the rest of a typical container-deployed software stack.

        Running everything as root. We never let your code run as root before, why is it now suddenly a good idea?

        This depends entirely on your threat model. We don’t run things as root because we have multiple security contexts and we want to respect the principle of least privilege. With containerised deployments, each container is a separate security context and already runs with lower privileges than the rest of the system. If your isolation mechanism works properly then the only reason to run as a non-root user in a container is if you’re running different programs in different security contexts within the container. If everything in your container is allowed to modify all state owned by the container then there’s no reason to not run it all as root. If you do have multiple security contexts inside a container then you need to think about why they’re not separate containers because now you’re in a world where you’re managing two different mechanisms for isolating different security contexts.

        1. 22

          I think you mean an image is a packaging format, whereas a container is an instance of a jail made up of various shared-kernel isolation mechanisims (including the wishful thinking) as you mentioned.

          Yes, the terminology is unfortunate. My reimplementation of Docker calls it an “instance” rather than “container”.

          1. 3

            yeah, the “’never run as root in your container” thing kills me

            1. 9

              IIUC that’s all because the way Linux isolates users (with the whole UID remapping into a flat range thing) is weird and there’s way too many security bugs related to that.

              1. 1

                I don’t know if this is still true, but part of where this advice comes from is that it used to be that running as root meant running as root on the host (i.e. the mechanism you’re talking about was not used by Docker). In theory this was “fine” because you could only get at stuff on the container environment, but it meant that if there was a container breakout exploit you were unconfined root on the host. So running as non-root in the container meant that you’d have to pair a container breakout with a privilege escalation bug to get that kind of access.

                In other words: the isolation mechanism did not work properly.

            2. 1

              That’s interesting. I haven’t actually bench tested the two in years. I’ll have to revisit it.

              1. 1

                You might want to have a look at NVIDIA’s enroot or Singularity for some lower-overhead alternatives. I’ve briefly looked at enroot after I saw the talk about Distributed HPC Applications with Unprivileged Containers at FOSDEM 2020, but sadly haven’t gotten a chance to use them at work yet.

                1. 2

                  Have you tried https://github.com/weaveworks/ignite to just run a docker image in a VM instead of a container?

                  1. 1

                    No, haven’t stumbled across that before. Thanks, that looks very interesting!

                    1. 1

                      That seems interesting. I wonder what benefit it provides compared to the shared-kernel isolation mechanism used by docker run <container>. Do I get stronger isolation, performance boost, or something else?

                      1. 2

                        I think there are always tradeoffs, but a VM may be easier to reason about than a container still. It’s a level of abstraction that you can apply thinking about a single computer to.

                        I do think that you get stronger isolation guarantees too. You can also more easily upgrade things, so if you have a kernel vulnerability that affects one of the containers, you can reload just that one. There are many issues that affect hypervisors only or guests only.

                        At launch we used per-customer EC2 instances to provide strong security and isolation between customers. As Lambda grew, we saw the need for technology to provide a highly secure, flexible, and efficient runtime environment for services like Lambda and Fargate. Using our experience building isolated EC2 instances with hardware virtualization technology, we started an effort to build a VMM that was tailored to run serverless functions and integrate with container ecosystems.

                        It also seems like a compromise between the user interface for a developer and an operations deep expertise. If you have invested 15 years in virtualization expertise, maybe you stick with that with ops and present a container user interface to devs?

                        For me, one of the big things about containers was not requiring special hardware to virtualize at full speed and automatic memory allocation. You’re never stuck with an 8GB VM you have to shut down to prevent your web browser from being swapped out when you’re trying to open stack overflow. You know 8gb was suggested, but you also see that only 512MB is actually being used.

                        Most hardware these days has hardware acceleration for virtualization and firecracker supports the virtio memory ballooning driver as of Dec 2020, so many of the reasons I would have used containers in 2013 are moot.

                        As an ops person myself, I find containers to often have an impedance mismatch with software defaults. Why show a container that is limited to two cores that it has 64 cores? Haproxy will deadlock itself waiting for all 64 connection threads to get scheduled on those two cores. You look in there and you’re like ‘oh, how do I hardcode the number of threads in haproxy now to two…’. It’s trivial with haproxy, but it’s not default. How many other things do you know of that use nproc+1 and will get tripped up in a container? How many different ways do you have to configure this for different runtimes and languages?

                2. 1

                  Containers can be deployed on VMs

                  OT because I agree with everything you said, but I have yet to find a satisfying non-enterprise (i.e. requiring a million other network services and solutions).

                  Once upon a time, I was sure VMware was going to add “deploy container as VM instance” to ESXi but then they instead released Photon and made it clear containers would never be first-class residents on ESXi but would rather require a (non-invisible) host VM in a one-to-many mapping.

                  1. 2
                    1. 1

                      We use this at my work (Sourcegraph) for running semi-arbitrary code (language indexers, etc.), it works really well.

                1. 8

                  The results really are kinda magic. I’m reminded of the posts from a while ago about blue noise.

                  I think you want to lighten the image slightly to make up for the extra black ink added. The after photo is darker than the before.

                  1. 1

                    Do you happen to have a link to the blue noise article?

                    1. 4

                      I was thinking of this one http://momentsingraphics.de/BlueNoise.html

                      Edit: Also really pretty and nice: http://www.joesfer.com/?p=108

                      1. 2

                        Thanks! It hasn’t been posted on Lobsters yet. Perhaps you should submit it if you find it interesting?

                    1. 4

                      Might want to take a look at this fun technique from RedHat for making your own distroless images (instead of relying on Google to do it, seeing as they haven’t updated Python 3 for years): http://crunchtools.com/devconf-2021-building-smaller-container-images/

                      1. 1

                        This is actually quite interesting, and I didn’t know “distroless” was even a thing. I prefer Debian for my base images, but Redhat certainly has the muscle to get some steam behind this idea, and at the end of the day the focus is more about the application and not necessarily the OS so should theoretically be agnostic anyhow.

                        1. 1

                          I don’t think this is particularly RedHat-specific, you could probably implement the same thing with Debian, you just need the ability to install packages into a specific root directory? Which dpkg at least does.

                      2. 2

                        I think that image still uses Python 3.7. Otherwise, it’s a good lightweight option.

                        1. 1

                          “Distroless” is an oxymoron. It might not be based on an existing well-known distribution but it’s still a distribution. You still rely on them to maintain the tooling that generates the image, receive security updates, and so forth.

                        1. 3

                          When we plugged the Razer device into Windows 10, the operating system automatically downloaded and installed the driver and the Razer Synapse software.

                          Can hardware vendors (and MitM) run whatever they want with elevated privilege on users’ Windows boxes by manipulating the driver installer? Please tell me the drivers are pre-approved by Microsoft and verified by a hash or something, otherwise that’s scary…

                          1. 6

                            Not only are the drivers vetted by Microsoft; Microsoft does some best-of-breed static analysis on their drivers, which is part of why Windows the kernel in 2021 is honestly rock-solid.

                            I have no idea about the control software, though. That didn’t even used to be a thing, so I’m not sure what the rules are.

                            1. 2

                              Unfortunately static analysis does miss things! So it would be nice to at least prompt and warn people: I’d argue that while Microsoft do a fine job this sort of thing is still partly a design issue.

                              Thanks for the interesting link to the driver verifier, I can see I’m off down a rabbit hole today…

                          1. 3

                            That’s a nice little trick. Note that you can also avoid installing dependencies with caching.

                            1. 1

                              yes, ive added a link to the documentation. It makes sense for small things like npm etc, but caching the complete /var/cache/apt/archives directory (to save download time) is probably not useful. One wants to test against the latest package versions and pulling in large amounts of packages, you might easily exceed the maximum cache size of 5 GB…

                              It makes also sense to set dpkg into unsafe-io option to save some time.. added another statement about this.

                              1. 2

                                Schemas and signatures have different purposes. Schemas are much more useful when you expect people to need/want to implement their own version of the protocol to better fit their requirements/needs/projects.

                                1. 1

                                  Could you elaborate? Why do you say that?

                                  1. 2

                                    Not OP, but I think @glacambre is saying that schemas are less specific than signatures, which grants implementors more freedom when implementing/maintaining one. Server-client architectures don’t even have an ABI, so we don’t need to worry about its compatibility. I can switch to another runtime/compiler or even another language whenever I want, as long as the protocol doesn’t change.

                                    Everything in an interface is a promise you shall keep indefinitely, so more expressiveness means more responsibility.

                                1. 18

                                  I personally prefer more tags to less tags, because I use tags to guide what to submit to Lobsters and what I want to read—often I’ll check out an otherwise-uninteresting title because the tags intrigue me. Also, more tags makes it easier to label submissions: does data science and modeling fit under math, compsci, what? Having a datascience tag makes the appropriate choice obvious.

                                  1. 3

                                    I agree. Even insanely specific tags like apple-m1, react, or language-model don’t hurt. Tags give users an option to filter out the topics they find uninteresting, and at the same time group related submissions together for the interested, so the more tags the better.

                                    Also, what about data-science instead of datascience? :)

                                    1. 1

                                      There is a sort of circular issue here though with tags being used to ‘guide’ what to submit, for example lobsters has traditionally been less keen on drive-by press releases about new versions of whatever framework (which I think is a good thing from an SNR pov), but the existence of a ‘release’ tag implies that that sort of thing is on topic here. I think in reality it’s shades of grey rather than being in the set of on-topics or not in the set, as defined by the existence of a tag. Likewise ‘culture’ and ‘practices’ seem to be catch-alls for traditionally off-topic, high noise stuff. In short I don’t think the tail should start to wag the dog, wrt the tag system and why you might come to this site rather than any of the others.

                                      I would tag datascience with math, fwiw. Datascience just being statistics done on a macbook, etc etc

                                      Having written the above, and seen my sibling comment about apple-m1 tags and the like, if you really need to go down the taxonomy rabbit hole can they at least be hierarchical, eg apple-m1 is a subset of ‘hardware’ and language-model is a subset of ‘plt’, for those that don’t want to fully explore the fractal tag-space, or think they can’t submit their article about nim verification because they can only see a haskell-verification and rust-verification tag.

                                    1. 1

                                      It’s a great read for me, but I don’t quite understand the following part:

                                      Since each closure has its own type, there’s no compulsory need for heap allocation when using closures: as demonstrated above, the captures can just be placed directly into the struct value.

                                      How does each closure having a distinct type eliminate the need for heap allocation? While i32 and Vec have different types, they both normally live on the stack (unless you explicitly use something like Box).

                                      1. 3

                                        He’s saying that since each has its own distinct type, there’s no inherent need to abstract them behind a trait object. They can be stored directly on the stack instead of being behind a trait object pointer (Box<dyn Trait> or &dyn Trait)

                                        1. 1

                                          Suppose |x| x + 1 and |x| x + 2 have the same type, then I can do something like vec![|x| x + 1, |x| x + 2], which seems to have the same effect of using trait objects?

                                          1. 2

                                            Those two closures do not have the same type. Here’s a Rust Playground example showing this. Each closure is compiled into its own struct which implements the correct traits (from Fn, FnMut, and FnOnce) and which (if they don’t capture from the environment) may be coerced to a function pointer. Their types, even if the closures are identical, are not the same.

                                            1. 1

                                              Exactly, and that’s why I said suppose they have the same type :P

                                              You pointed out that each closure having a unique type lifts the restriction that closures must be put behind a trait object, and I was saying there is no such restriction even if all closures with the same signature share one common type, because in that case we can do stuff like vec![|x| x+1, |x| x+2] which normally calls for trait objects.

                                              1. 2

                                                From a type system pov you’d have two different implementations of Fn/FnMut for the same type, since you want different function bodies each. That would be kind of weird. If you then put two instances into the same vec I’m not entirely sure how Rust would find the correct trait impl without adding extra markers on the struct. Which smells like dynamic dispatch already.

                                                1. 1

                                                  I suppose the compiler can look at the closures and figure out the least restrictive trait for each closure (can I make this Fn, No? then what about FnMut?Also no? Well I guess it’s a FnOnce then) and find the greatest common divisor of all closures in the Vec.

                                                  1. 2

                                                    That’s not the issue. Even if there was only one trait for all, you would have overlapping implementations of the trait. The traits have a call method that will need to be implemented differently, one for x+1 and one for x+2.

                                                    1. 2

                                                      Oh, I see. In the case where some closures share a common type, instances of that type may include an additional field holding the pointer to its function body, which is essentially dynamic dispatch. That doesn’t call for heap allocation though, because the function pointers typically refer to .TEXT instead of the heap.

                                                      EDIT: I realized that if you put the instruction for a closure on the stack, then it would not have 'static lifetime and thus cannot be returned from a function. See more discussion here.

                                      1. 3

                                        Lobsters isn’t write-only. Submit other stuff, too, or comment on other people’s submissions.

                                        EDIT: wait a sec, this article is from March. You’ve published ten things since then, and your Lobsters submissions are just in reverse chronological order. Are you just posting your entire archives to Lobsters? Is this just a inbound channel?

                                        EDIT2: From your homepage:

                                        I give you the strategy, technology, and skills to become a trusted brand […] Marketing gurus are a dime a dozen. My approach is different – think of me as a sparring partner who will sharpen your skills and plan your attack. We’ll work together to create a cohesive strategy, technology and tools that inspire long-term connections and fuel sustainable growth. It’s about trust. It’s about reputation. It’s about telling your story in a way that gets results.

                                        1. 2

                                          Lobsters isn’t write-only. Submit other stuff, too, or comment on other people’s submissions.

                                          I don’t understand: why can’t a user submit their own content exclusively, as long as the submissions are of high quality? From my perspective, well-received self-marketing materials are still a contribution to the community, even if the author themself may benefit from the submission.

                                          1. 3

                                            It’s not a hard and fast rule.

                                            @hwayne is doing OP a favor by giving them a heads-up.

                                            1. 3

                                              Good question. From Mitigating Content Marketing:

                                              We now consistently average over 20k visitors per weekday. Programming is an enormous, growing, lucrative, powerful industry and thus a very expensive demographic to advertise to. A link on our homepage sends traffic that would otherwise cost $15-30k on Twitter, AdWords, or LinkedIn.

                                              When this is sending attention to celebrate someone advancing the state of our understanding or sharing what they’ve created, it’s the internet at its best as gift economy. Unfortunately, some people see the site as a handful of rubes naively standing around a money fountain, so why not try to take a taste?

                                              People who are only submitting their own content exclusively are overwhelmingly (not entirely, but overwhelmingly) bad-faith actors who are just using us for free advertising. People who are commenting or submitting other stuff are at least making an effort to participate in the rest of the community.

                                              I’m being a bit harsher with this comment, because I was more polite with my comment on his previous story:

                                              Welcome to lobsters! Generally we encourage people to post and comment on articles they haven’t written, too, to participate more in the community.

                                              So either he’s not reading comments, which means he’s just spamming, or he read my comment and doesn’t care, in which case he’s bad-faith.

                                              1. 4

                                                Hey, I am verry sorry that my actions were seen as spammy behaviour, that was not my intention at all. I’ve been reading the philosophy section of lobsters for years and just wanted to contribute a few ideas myself.

                                                I’ll try to submit some other interesting links as well in the future and try to be more active with the comments.

                                                Thanks

                                                1. 3

                                                  People who are only submitting their own content exclusively are overwhelmingly (not entirely, but overwhelmingly) bad-faith actors who are just using us for free advertising.

                                                  Sure, but let’s not confuse heuristics with what those heuristics are trying to detect. This particular case feels suspect to me, since the site features a few CTAs for paid services. But I think it’s important to point out that it’s not inherently a bad faith action to only post articles to your own blog. The issue is when the content is trying to make a sale. There’s clearly grey area between “good faith posting of excellent content that only I have written” and “posting on your forum in order to sell you something”. And since we can’t read minds, I think that:

                                                  Submit other stuff, too, or comment on other people’s submissions.

                                                  …demanding engagement from someone like this seems unnecessarily hostile, setting a negative tone for newcomers. Why not just flag as spam, provide the feedback, and then let the mods take action if needed? For example, “you seem to only be posting links to your blog which is also trying to sell me services. this isn’t a place for content marketing, and people get banned for it pretty regularly. check out this post for background”

                                                  1. 5

                                                    For example, “you seem to only be posting links to your blog which is also trying to sell me services. this isn’t a place for content marketing, and people get banned for it pretty regularly. check out this post for background”

                                                    Man, that’s much better copy. Strikes the right balance of polite without being too “nice”. Gonna use that instead from now on

                                            1. 5

                                              tl;dr; They are sum types just like in Swift or F#.

                                              1. 5

                                                I hope we are going to see a post about how Rust immutability is amazing soon. After that we can have articles about every single ML feature that existed for decades that Rust successfully implemented.

                                                1. 8

                                                  You mean, it’s not a good thing to implement great features of a language that basically nobody is using into a new language that makes things better and more appealing?

                                                  1. 2

                                                    No, I mean presenting it as a novel idea when in fact it is around for 30 years is kind of funny.

                                                    that basically nobody is using into a new language

                                                    Factually incorrect. Please have a look at the languages in the ML family.

                                                  2. 4

                                                    It’s no secret that Rust was heavily inspired by ML, C, C++, etc. Rust itself has very few new language features, the borrow checker being one of them.

                                                    But Rust appeals to the low-level systems crowd, and brings with itself a ton of nice-to-haves from ML and the like. So people who were previously stuck with C-like enums suddenly have nice options and want to talk about it.

                                                    1. 4

                                                      What’s so bad about highlighting the strengths of a programming language?

                                                    2. 2

                                                      PEP 634 is also bringing sum types to Python.

                                                    1. 2

                                                      UNIX uses the term file descriptor a lot, even when referring to things which are clearly not files, like network sockets

                                                      Nit: unix uses the term ‘file’ a lot, including to refer to things that are not persistent, hierarchically-accessed records, like network sockets.

                                                      1. 1

                                                        From my understanding, a file in Unix’s sense is essentially a stream of bytes.

                                                        1. 1

                                                          The term is not entirely well-defined (which is part of the problem). I think that, at the very least, a file encompasses a stream of bytes, but there are files which are not simply streams of bytes. Anything that can be ioctled, for instance.

                                                      1. 12

                                                        What ever happened with the dispute over attribution with regards to this and that third party package manager?

                                                        1. 9

                                                          Like a modern day David vs. Goliath, David lost.

                                                          1. 6

                                                            On the github:

                                                            We would like to thank Keivan Beigi (@kayone) for his work on AppGet which helped us on the initial project direction for Windows Package Manager.

                                                            IIRC Beigi at one point said that was enough for him.

                                                            1. 7

                                                              The fundamental rule for URLs is that they should not change. So if the https://lobste.rs/t/formalmethods will remain (as redirection), it is OK.

                                                              1. 4

                                                                I agree! However, https://lobste.rs/t/cryptocurrencies returns 404 after cryptocurrency was renamed to merkle-trees :(

                                                                1. 4

                                                                  @pushcx Is it possible to create a redirect for renamed tags?

                                                                  1. 1

                                                                    Could always hard-patch in a route in the top or /t/ routers.

                                                              1. 8

                                                                Would this also apply to other tags, in general, like obectivecobjective-c?

                                                                1. 15

                                                                  Yeah, I would also second that.

                                                                  An alternative is to rename merkle-trees to merkletrees so that it’s consistent with other hyphen-less tag names, but I personally prefer the presence of delimiters.

                                                                  1. 2

                                                                    Can always take the Chaotic Good approach and retrofit the rules so names in tags are followed (and preceded?) by hyphens.

                                                                    1. 3

                                                                      I propose that names in tags be followed by hyphens only if they end in an “odd” letter (counting starting from 1), so merkle-trees-, formalmethods-, objective-c-, rust, etc.

                                                                      1. 1

                                                                        Just strip the hyphens. I want o-b-j-e-c-t-i-vec to be valid, damnit!

                                                                        1. 8

                                                                          ObjectiVec is the name of my next OO vector library.

                                                                  1. 7

                                                                    Can’t we just inject noises into that register as mitigation? From my understanding, s3_5_c15_c10_1 is accessible to all applications, so it should be easy to overwrite.

                                                                    1. 9

                                                                      Towards the end there is a paragraph on the webpage with words to that effect saying it wouldn’t mitigate it, something about doing so would peg the CPU at 100% and still not make the register useless.

                                                                      Then again the whole point of the webpage is to poke fun at infosec and ultimately goes on to say this isn’t a big deal and people shouldn’t be worried.

                                                                      1. 3

                                                                        I think this would technically work, but need one process per cluster running to do it so there would be significant power use and CPU capacity costs.

                                                                        1. 5

                                                                          Also, using forward error correction, you can still reliably transfer data at a lower rate, even when some noise is injected. How much lower the rate will be depends on how much noise is injected. I think with that, even if you would be willing to sacrifice a significant amount of power and CPU, this would not work as a practical mitigation.

                                                                      1. 6

                                                                        Very interesting but I remain unconvinced. It seems as though once you start adding the required features for productionization the models converge.

                                                                        The obvious way to improve throughout in a pull based model is to the have producer prefetch a buffer. This mimics the buffer that would exist on the DAG consumers in the push-based model. (In fact it may be better as it is naturally shared amount consumers.) In many real-world systems you will need to add back pressure to the producer in a push-based model, leading to it being basically equivalent to the pull-based model with buffering. (again, except the buffers are in the consumers).

                                                                        The author does raise an interesting point though, PostgreSQL and CockroachDB materialize the entire table when using with classes. In the past I have heard is that this is treated as some sort of optimization hint in PostgreSQL so I wonder if there is something fundamental about the model that is holding it back, or if it is a “feature” that it works this way.

                                                                        1. 3

                                                                          PostgreSQL used to materialize WITH clauses unconditionally, and it was often used as a mechanism for hand-optimizing queries. But as of PostgreSQL 12, by default it only materializes them if they are used more than once, are recursive, or have side effects. Otherwise it folds them into the main query for purposes of generating a query plan. If you still want to use them for manual optimization, you can explicitly say whether to materialize them.

                                                                          1. 2

                                                                            +1 Insightful. This is approximately my take too. I’ve written query engines and I opted for something that’s kind of a mix: Next() and Check() being the respective primitive operations to pull and push. The buffer you mention is a materialize operator that’s a logical noop to the plan but something the optimizer can add where it sees fit.

                                                                            That said, there may be something to leaning more push than I have been, specifically for DAGs, which require hacks in a pull model. Furthermore, in a distributed setting, push works a better because there’s much less back-and-forth. Tradeoff there is throwing a ton of data over the network. Still needs a hybrid.

                                                                            If you find it interesting, let me know what specifically, maybe I’ll put it on my blogging stack.

                                                                            1. 1

                                                                              I guess I’m late to the discussion, but what about coroutines, which appear to be the solution to all producer/consumer problems?

                                                                            1. 28

                                                                              Perhaps related: I find that a certain amount of redundancy is very useful for error checking, both by the speaker/author and listener/reader. This might take several forms:

                                                                              • I repeat myself often when giving talks or writing, so you never have to jump too far back to an earlier point in time / space. If I say something that is very similar but slightly different than before, I’m either doing it to draw attention to an intentional change, or I’ve made a mistake! Either way, people are paying attention closely to the difference.

                                                                              • When writing math, I never rely on symbols or words alone, but a mixture of both. The rule I follow is that you should be able to understand the sentence even if most of the symbols are deleted. This is invaluable for catching mistakes, and also for establishing notation – using words alone can be imprecise, and using symbols alone might be disorienting for a student or for someone familiar with slightly different conventions. The document should be skimmable, and every theorem should be more or less self-contained.

                                                                              • When writing code, I prefer to comment each logical block with some explanation of “what, why, how”, even if an educated reader might be able to infer from context. The point is that if their inference about the code does not match my comments, then they can confidently conclude the code has a bug, and it’s not just some mysterious hack they should be afraid of changing. Yes, this means maintaining comments along with the code, but I find that to be good practice anyway.

                                                                              A good way to summarize might be: When communicating, it’s important to keep in mind the predictions / assumptions your audience will make about your speech / writing. They’ll spend a lot of cognitive effort working through the things you say that don’t match their predictions. So, make sure you only surprise them with the new information you’re trying to communicate, rather than potential distractions like unfamiliar notation or syntax. (non-standard notation is ok and sometimes preferable, but the meaning should be evident from context!)

                                                                              1. 9

                                                                                The rule I follow is that you should be able to understand the sentence even if most of the symbols are deleted.

                                                                                As someone bad at math, I appreciate you.

                                                                                1. 12

                                                                                  Heavy use of symbols is an underappreciated roadblock for a lot of people who might otherwise be able to grasp math concepts, I think.

                                                                                  As someone who didn’t study math beyond basic calculus, I’ve had the experience of being confronted with a page full of unfamiliar glyphs and having no idea what to make of it, but then understanding the idea just fine once someone translated it to English for me.

                                                                                2. 5

                                                                                  In one concrete example, I try to never use “former” and “latter” to refer to previous things because it requires a jump. You can usually summarize the options in a small phrase.

                                                                                  1. 3

                                                                                    I wonder how many, like me, have to go through mental gymnastics to separate “former” and “latter”. I know latter comes after former because of the resemblance to “later”.

                                                                                    1. 2

                                                                                      I use the same mnemonic!

                                                                                      Though I wouldn’t go so far as calling it gymnasgics (for me personally), I do think it inherently causes a pause to backtrack and re-parse.

                                                                                      Another point for the Finnish language because of having a tighter coupling to all the other words referring to something earlier or later. I can’t remember how this is properly expressed in German or French, but Swedish also gets this quite correct.

                                                                                      English just makes it unnecessarily difficult.

                                                                                      1. 2

                                                                                        I thought the English construction was somehow derived from French (or Norman, rather) but apparently it’s from Old English if this blog post is to believed: https://www.grammarly.com/blog/former-vs-latter/

                                                                                  2. 2

                                                                                    This is an underrated statements. I find that the “avoid needless words” sentiment does more harm than good, even in fiction, and can be disastrous in technical writing.

                                                                                    Human speech naturally has some redundancy in it, and the higher the probability of errors and the higher the cost of those errors, the more redundancy is required. Clarity and redundancy aren’t mutually exclusive, sometimes clarity is redundancy.

                                                                                    1. 1

                                                                                      The point is that if their inference about the code does not match my comments, then they can confidently conclude the code has a bug, and it’s not just some mysterious hack they should be afraid of changing.

                                                                                      Nitpicking: what if it’s the comments that are incorrect or out of sync with the code? With both code and comment, now you have two sources of truth…

                                                                                      1. 9

                                                                                        Exactly! If the code doesn’t do what the comments say it does, whoever is reading will file an issue and the matter will be sorted out. This redundancy is really helpful for hunting down bugs and avoids two problematic scenarios:

                                                                                        1. If someone has changed the code but not the comment, they probably didn’t do a thorough enough job reading the surrounding context to actually understand the impact their changes will have on the rest of the code. So they’ve either introduced a bug, or they forgot to verbally explain the reason for their changes, which itself warrants a bug report.

                                                                                        2. I feel that code takes on just as much (or more) technical debt when the documentation is missing as when the documentation is incorrect. Incorrect documentation (as long as it is colocated with the code it describes) can act as a big red flag that something is wrong. When documentation is missing, anyone who attempts to modify the code will be afraid to make any changes, afraid that the suspicious lines really do serve some mysterious purpose that they just don’t understand yet. If someone is afraid to make changes, they might instead add code to wrap the mysterious bits

                                                                                        Some caveats:

                                                                                        • It does take some discipline to work this way, and I haven’t tried enforcing this style in large codebases / large teams. I have seen it work well on smaller projects with one or two like-minded collaborators. It’s especially useful on solo projects where I might work on the project in bursts of a few days once every few months. This way I document my in-progress thought process and can be more confident that local changes to the code will work as intended, even if I haven’t touched the code in three months.

                                                                                        • For documentation that is not written inline with the code itself, and intended to be consumed by users of the software, not developers, I feel differently about missing vs incorrect documentation. In this scenario, it’s much harder to keep the documentation in sync, and incorrect documentation is more dangerous.

                                                                                        1. 4

                                                                                          I think that’s the point, just like parity bits on memory. At least you know something isn’t right.