1. 9

    On this subject, I think the addition of low latency garbage collectors to the JVM (Shenandoah and ZGC) has made JVM applications super attractive again for networked services. People who use Clojure tend to really like it so I’m glad there is still a lot going on in the community.

    1. 1

      I think it’s weird that in TypeScript I can’t do foo?.bar for any bar on any object. Let me explain with an example.

      function doStuff(x: unknown) {
          const field = x?.field ?? 0
          // do some stuff

      Why should the compiler bitch at me about this? I know x is unknown, but it might have field as a field. I access it with the optional operator, so it should be fine. This isn’t just unknown, either- you’ll get the same error with other types that aren’t guaranteed to have the field, such as an interface or object.

      Sure… you probably shouldn’t be doing that often, but it’s not wrong, IMO.

      1. 3

        If typescript allowed accesses to properties that aren’t defined in the type, you’d lose the ability to catch typos in field names.

        The unknown type is IMO a little flawed in that tsc makes it a little harder than it ought to be to narrow it down to anything else with guards.

        1. 1

          That’s a great point. Thank you. I can’t believe that I hadn’t considered that.

          I was just frustrated that the mental model of JavaScript objects basically being dictionaries doesn’t really translate to TypeScript.

          I do still think (and agree with your last statement) that it should be easier to work with unknown objects. It’s a pain in the butt to have to type if ("foo" in x) { x.foo }, especially because TypeScript, like JavaScript, is all statement-based, so if isn’t an expression. Just makes everything more tedious.

          1. 1

            When I’m working with unknown in practice, I almost always define guard functions to get around the holes. Obviously they introduce more problems if they happen to be buggy but, ah well.

            function isObject(obj: unknown): obj is object {
              return typeof obj === "object" && obj !== null;

            Ternaries are expression-level, so "foo" in obj ? x.foo : null would work? Type narrowing propagates from the left hand sides of x?y:z, x||y and x&&y to the right hand sides .

            1. 1

              Does your guard function actually have to check for null? If the type of obj is “object”, can it possibly be null? What about undefined (which unknown could also be)?

              IIRC, object type doesn’t make my situation better, either. I think it’s also “opaque” to dot-notation field access. I think I just need to define a simple function for these places, but it’s kind of a bummer that I have to do that. Not a huge deal, just a “papercut” kind of thing.

              1. 1

                typeof null === "object" is one of the famous stupid-looking things in JavaScript that probably can’t be changed ever.

                typeof undefined === "undefined" though, so that one’s fine.

                Yeah object doesn’t get you much (and I can’t remember if I meant to use Object) but it’s much less hostile than unknown for further narrowings.

                A nice thing I’ve tried at work recently is using a library like yup to check large objects all in one go, like:

                interface Foo {
                  x: number;
                  y: number;
                  name: string;
                const fooSchema = yup().object({
                  x: yup.number.required(),
                  y: yup.number.required(),
                  name: yup.string.required(),
                const isFoo = (obj: unknown): obj is Foo => fooSchema.isValidSync(obj);

                Transcribing the TS type manually into yup is a little boring but easy enough.

        2. 1

          In a user typed system, any object without a type must be opaque. Otherwise you’d have a type for “might have field.”

          1. 1

            I think you want any, not unknown. Then it will compile.

            1. 1

              Not quite. any is too permissive. That would allow me to just assume the field is definitely there. any more-or-less turns off all of the type checking of TypeScript, which isn’t quite what I want. I want a safe way to say “give me this field if the object has it, or give me undefined if it doesn’t” without a verbose if-statement to check first.

              1. 1

                That’s what it does (check the compiled output). If you want any deeper checking, you probably have to use types, since it is the types that typescript is checking. :)

            2. 1

              Sorry, couldn’t you just do x.field || 0? This works in JavaScript, not sure if it does in Typescript.

              1. 1

                Well, I have all of the strict compiler settings turned on, so I’m not 100% positive if that’s ever allowed in TypeScript, but for me it isn’t allowed. You cannot use dot-notation on an unknown type until you cast it (or “type narrow” it) to something else.

            1. 20

              To some degree, I feel the same about open source. The brand won big time, but not because it truly disrupted software development, but because big tech could not completely shut free software down and so they embraced a toned down version of it and, one marketing campaign at a time (eg Microsoft ❤️ Open Source), they progressively diluted it even more.

              1. 6

                This reminds me of a recent talk by Bruce Perens where he essentially says that open-source is just “you” doing free work for big corps ; but hey you get a free code-forge to share the code you wrote in your free IDE, often in your free time. /s

                1. 1

                  As the other Kristof, I have to ask, was open source a poison pill “dilution” of free software, or is it that more people were more interested in licenses compatible with proprietary software and so open source was inevitably going to win out over free software in the end?

                  1. 3

                    License compatibly is not the difference, the licenses are the same (there is a 100% overlap between free software and open source licenses) the difference is in focus on user / kind of user. Free Software thinks “how can we empower everyday computer users” and open source thinks “how can I get more eyes in this library”, broadly speaking.

                    1. 1

                      there is a 100% overlap between free software and open source licenses

                      I’m not sure if you understand what I’m saying. Proprietary software is compatible with open source software. Proprietary software is not compatible with free software (your software inherently becomes free, i.e. you must give customers the source code if they ask for it).

                      1. 1

                        your software inherently becomes free, i.e. you must give customers the source code if they ask for it

                        Are you talking about copyleft? Because that’s not the same thing as Free Software. copyleft licenses are also valid open source licenses also, and non-copyleft licenses are often recommended by the Free Software Foundation for various purposes.

                        1. 1

                          Yes, I am talking about copyleft licenses. I’ve always interpreted “free” to mean “free as in libre”. I did not know the fsf ever recommended non copyleft except as a reluctant compromise to business realities.

                          1. 1

                            Yeah, “free as in libre” is well-defined and does not mean the same thing as copyleft. Free, libre, Free Software, all defined by the FSF or the GNU community have always included copylefted works of course, but nothing about the four freedoms requires copyleft. Rather, copyleft is one of many strategies to use in our effort to bring freedom to the world.

                            The difference between Freedom and Open Source is one of philosophy and practise, not one of licensing. The OSI and the FSF publish almost identical license lists. The differences are even fading since usually half or more of the OSI board is freedom fighters these days. But in general the main thing is that a library meant for professional developer use is probably “open source” whereas an application or system that gives end users their freedom is “Free Software”. There are other ways to characterize this philosophical difference of course, but that’s one easy one.

                1. 8

                  To be somewhat cynical (not that that is new), the goal of the ’10s and ’20s is monetization and engagement. Successful software today must be prescriptive, rather than general, in order to direct users to the behaviors which are most readily converted into a commercial advantage for the developer.

                  I agree with the article but just to play devil’s advocate, I think the death of these halfway “it’s not programming but they’re still flexible building blocks” attempts at democratized personal computing ran into two realities:

                  1. Normal people don’t want to program, not even a little bit, because it tends to get complicated fast. GUIs are more intuitive and picking one up for its intended task is usually very fast. UX research has come a long way.
                  2. Programming is actually way more popular than ever, and when people do pick it up, they tend to want to go all the way, using Python, or even “enterprise” languages. And if you do just pick up python and learn how to start doing the things you want to use it for, the world has only gotten friendlier: cheap cloud hosting, heroku, a golden era of open source software, raspberry pis, and so on.
                  1. 8

                    There’s also a lot more consumer computing too. People who bought computers in the 80’s were likelier to use it for business stuff, even a small one. My parents bought a computer for the first time in ~1997 solely for the internet and CD-ROMs like Encarta or games. They’d have no use for databases, and wrote with a pen instead of a word processor.

                    Also as a counterpoint: As much as SaaS is reviled, it also does deliver in its absolution of many responsibilities like maintenance, providing a readymade service, and being a service instead of liability for taxation.

                  1. 3

                    There’s definitely a fundamental tension between web pages as documents (which should last for a very long time and be immune to bitrot) versus web pages being deliverable, dynamic applications. The latter deserves churn and the former deserves stability. Not sure how to reconcile but I think JSON APIs are ironically a step in the right direction, because the application just becomes a view for http-gettable content. Maybe we can get people to start storing xml documents again?

                    1. 1

                      The peak of that tension is that if I send someone a link to a site I intend to share as a static document, they might get the webpage, or an application, or something different entirely — depending on a number of hidden variables. The conversation goes on, but we might not have seen even remotely the same thing. While a surefire recipe for confusion and misunderstanding, the consequences from that can run deep and shatter relationships; verification costs time and is not exactly a natural thing in informal communication.

                    1. 3

                      Another interesting way to look at this is that PyPy gets within 5x the speed of the Rust version. It’s a great project.

                      1. 7

                        I find it sad that the sister bill in the UK that was just passed explicitly excludes cellphones and computers (someone please correct me if I’m wrong).

                        1. 1

                          It’s true and it would be a good example of British humor if it wasn’t so sad.

                        1. 6

                          Honestly, I don’t know anymore…

                          1. 10

                            Minimal Version Selection itself is fine, in my experience neither better nor worse than what I guess is the de facto standard of… Maximal {Patch, Major} Version Selection? It biases for churn reduction during upgrades, maybe, which at least for me doesn’t have much net impact on anything.

                            But a lot of the ancillary behaviors and decisions that come with MVS as expressed in Go modules are enormously frustrating — I would go so far as to say fundamentally incompatible with the vast majority of dependency management workflows used by real human beings. As an example, in modules, it is effectively not possible to constrain the minor or patch versions of a dependency. You express module v1.2.3 but if another dependency in your dep graph wants module v1.4.4 you’ll get v1.4.4. There is no way to express v1.2.x or v1.2.3+. You can abuse the require directive to lock to a single specific version, but that constraint isn’t transitive. And module authors can retract specific versions, but that power is not granted to consumers.

                            edit: for more of my thoughts on this exciting topic see Semantic Import Versioning is unsound

                            1. 5

                              I would go so far as to say fundamentally incompatible with the vast majority of dependency management workflows used by real human beings.

                              I hope that this post with the experience reports of many real human beings claiming that it works well for them will help you reconsider this opinion. Perhaps it’s not as much of a vast majority as you think it is.

                              1. 3

                                None of the experience reports really speak to the points I raise. Maybe that’s your point.

                              2. 2

                                The position of the Go team is (was?) that packages with the same import path must be backwards compatible. I guess their point is that 1.4.4 should be compatible with 1.2.3, but that’s not how the rest of the software world has worked in the past decade. It’s a big if, but if all the go programmers agree, it works.

                                1. 6

                                  That’s not (only?) the position of the Go team, it’s a requirement of semantic versioning. People fuck it up all the time but that’s the definition. One way to look at the problem with modules is that they assume nobody will fuck it up. Modules assumes all software authors treat major version API compatibility as a sacrosanct and inviolable property, and therefore provides no affordances to help software consumers deal the fuckups that inevitably occur. If one of your dependencies broke an API in a patch version bump, well, use a better different dependency, obviously!

                                  Ivory Tower stuff, more or less. And in many ways Go is absolutely an Ivory Tower language! It tells you the right way to do things and if you don’t agree then too bad. But the difference is that if you don’t like the “I know better than you” decisions that Go the language made, you can pick another language. But if you don’t like the “I know better than you” decisions that modules made, you can’t pick another package management tool. Modules has a monopoly on the space. That means it doesn’t have the right to make the same kind of normative assumptions and assertions that the language itself makes. It has to meet users where they are. But the authors don’t understand this.

                                  1. 3

                                    Semantic versioning is, unfortunately, incompatible with graceful deprecation. Consider the following example:

                                    • A is the version you’re using.
                                    • B introduces a new API and deprecates an old one
                                    • C removes the deprecated API.

                                    In SemVer, these thing would be numbered something like 1.0, 1.1, 2.0. The jump from 1.1 to 2.0 is a breaking change because the old API went away at that point. If you paid attention to deprecation warnings when you upgraded to 1.1 and fixed them then the 1.1 -> 2.0 transition is not a breaking change though and SemVer has no way of expressing this with a single exported version and this leads to complex constraints on the import version (in this three-version case, the requirement is >=1.1, <3.0). A lot of these things would be simpler if APIs, not packages, were versioned and the package advertised the range of the API that it advertised. Then you’d see:

                                    • A is the 1.0 API
                                    • B supports the 1.0 API and the 2.0 API
                                    • C supports the 2.0 API

                                    As a consumer, I’d just specify that I need the 1.0 API until I’ve migrated my code and then that I need the 2.0 API.

                                    1. 1

                                      One way to look at the problem with modules is that they assume nobody will fuck it up.

                                      So does everyone else in the world who builds with ^version and no lock file, except for them, the breakage happened when the author of their dependency published a new version rather than when they themselves performed a conscious action to alter dependencies in some way.

                                      1. 3

                                        Yeah but in most package management systems you can pin specific versions.

                                      2. 1

                                        […] and therefore provides no affordances to help software consumers […]

                                        If one of your dependencies broke an API in a patch version bump, well, use a better different dependency, obviously!

                                        You can use an exclude directive to remove the breaking version from consideration. If upstream delays fixing the breaking change, you can fork the last good version and use a replace directive to substitute your own patched module in place of the old module.

                                        It’s hard to imagine this hypothetical happening, however (and please correct me if I’m wrong). MVS selects the maximum of minimum required versions. If some module called “broken” patches and the new version breaks your own software, there is no way for that update to propagate to your software unless both 1) a different dependency of your module called “dep” decides to start requiring the new version of “broken” and 2) you update your dependencies to require the updated version of “dep”. (1) Implies that “dep” truly requires the patch (that broke your code), and (2) implies that you truly require the new features in module “dep”. By transitivity… there is no conceivable way to fix the problem without patching it yourself and replacing.

                                        There’s actually a whole paragraph on this topic of “high fidelity” in Russ Cox’s original blog post about the version selection algorithm.

                                        1. 2

                                          You can use an exclude directive to remove the breaking version from consideration.

                                          I meant “broke an API” in the “API compatibility” sense, not in the “wrote a bug” sense. That kind of broken carries forward.

                                    2. 1

                                      So your article states: “It’s a contract with its consumers, understood by default to be supported and maintained indefinitely.”

                                      I don’t think this follows from anything you have written or anything I have read about SIV. The way SIV works sounds to me like if you want to deprecate features from your library you should provide a reasonable deprecation policy which includes a time period for which you will provide bug-fixes for the old major version and a time period for which you will backport security-fixes for the old major version at which point you stop supporting that version since you’ve done the best you could to get old users moved to a new version. This to me seems like a lot of major software (not written in the past 5 years) basically works.

                                      “At Google, package consumers expect their dependencies to be automatically updated with e.g. security fixes, or updated to work with new e.g. infrastructural requirements, without their active intervention.”

                                      I expect this to happen on my linux desktop too. I don’t see a difference in expectations there.

                                      “Stability is so highly valued, in fact, that package authors are expected to proactively audit and PR their consumers’ code to prevent any observable change in behavior.”

                                      I think if you feel like writing a library/module/dependency then this is the kind of mindset you are obliged to take. Anything short of this kind of approach to writing a library/module/dependency is irresponsible and makes you unqualified to write libraries, modules or dependencies. This, to me, seems to have been the mindset for a long time in software until languages came along with language package managers and version pinning in the last few years. And I don’t think that this has been a positive change for anyone involved.

                                      “As I understand it, even issues caused by a dependency upgrade are considered the fault of the dependency, for inadequate risk analysis, rather than the fault of the consumer, for inadequate testing before upgrading to a new version.”

                                      And I agree with this wholeheartedly, in fact this is the mindset used by users of linux distributions and distribution maintainers.

                                      “Modules’ extraordinary bias toward consumer stability may be ideal for the software ecosystem within Google, but it’s inapproriate for software ecosystems in general.”

                                      I think it’s not inappropriate, it’s totally appropriate. I just think that modern software ecosystems have gotten lazy because it’s easier than doing it right (which is what google seems to be advocating for a return to).

                                      I should say, I don’t disagree with the point you make that intrinsically linking the major version to the package name is a good idea. Go should definitely NOT do that for the reasons you outlined. It would also be an easy indicator for me when picking a project to use in my codebase: Is the codebase on major version 156? Yes? Then I probably don’t want to touch it because the developers are not taking the responsibility of maintaining a dependency very seriously.

                                      People who want to play in the sandpit of version pinning and ridiculously high major version numbers because they think software development is an area where no thought or effort should be put into backwards compatibility should be welcome to use whatever language they want to without being artificially limited.

                                      Now, conversely, I would say, there seems like an obvious solution to this problem too. If you want to use semver while keeping to the golang rules, why not just encode the real semver version within the go version: “0.015600310001”. Sure, it’s not exactly so human readable, but it seems to encode the right information and you just need to pretty print it.

                                      “Additionally, policies that bias for consumer stability rely on a set of structural assumptions that may exist in a closed system like Google, but simply don’t exist in an open software ecosystem in general.”

                                      I will take things back to the world of linux distributions where these policies actually do seem to exist.

                                      “A bias towards consumers necessarily implies some kind of bias against authors.”

                                      Yes, and this is a good thing. Being an author of a dependency is a very big responsibility and a lot of modern build systems and language package managers fail to make that very clear

                                      “But API compatibility isn’t and can’t be precisely defined, nor can it even be discovered, in the P=NP sense.”

                                      This is true, but in reality there’s a pretty big gulf between best effort approaches to API compatibility (see: linux kernel) and zero effort approaches to API compatibility (see: a lot of modern projects in modern languages).

                                      “Consequently, SIV’s model of versioning is precisely backwards.”

                                      Actually it would be semver’s fault not SIV’s surely.

                                      “Finally, this bias simply doesn’t reflect the reality of software development in the large. Package authors increment major versions as necessary, consumers update their version pins accordingly, and everyone has an intuitive understanding of the implications, their risk, and how to manage that risk. The notion that substantial version upgrades should be trivial or even automated by tooling is unheard of.”

                                      Maybe today this is the case, but I am pretty sure this is only a recent development. Google isn’t asking you to do something new, google is asking you to do something old.

                                      “Modules and SIV represent a normative argument: that, at least to some degree, we’re all doing it wrong, and that we should change our behavior.”

                                      You’re all doing it wrong and you should change your behavior.

                                      “The only explicit benefit to users is that they can have different versions of the “same” module in their compilation unit.”

                                      You can achieve this without SIV, SIV to me actually seems like just a neat hack to avoid having to achieve this without SIV.

                                      In any case, I think I’ve made my point mostly and at this point I would be repeating myself.

                                      I wonder what you think.

                                      1. 1

                                        People who want to play in the sandpit of version pinning and ridiculously high major version numbers because they think software development…

                                        …is a means and not an end are the norm, not the exception. And the fact that people work this way is absolutely not because they’re lazy, it’s because it’s the rational choice given their conditions, the things they’re (correctly!) trying to optimize for, and the (correct!) risk analysis they’ve done on all the variables at play.

                                        I appreciate your stance but it reflects an Ivory Tower approach to software development workflows (forgive the term) which is generally both infeasible and actually incorrect in the world of market-driven organizations. That’s the context I speak from and the unambiguous position I’ve come to after close to 20 years’ experience in the space, working myself in a wide spectrum of companies and consulting in exactly these topics for ~100 orgs at this point.

                                        Google has to work this way because their codebase is so pathological they have no other choice. Many small orgs, or orgs decoupled from typical market dynamics, can work this way because they have the wiggle room, so to speak. They are the exceptions.

                                        1. 1

                                          the things they’re (correctly!) trying to optimize for, and the (correct!) risk analysis they’ve done on all the variables at play


                                          At least don’t call the majority of software developers “engineers” if you’re going to go this way.

                                          The fact that this is considered an engineering discipline with such low standards is really an insult to actual engineering disciplines. I can totally see how certain things don’t need to be that rigorous, but really, seriously, what is happening is not par for the course.

                                          The fact that everyone including end users has become used to the pathological complacency of modern software development is really seriously ridiculous and not an excuse to continue down this path. I would go so far to say that it’s basically unethical to keep pretending like nothing matters more than making something which only just barely works within some not even that optimal constraints for the least amount of money. It’s a race to the bottom, and it won’t end well. It’s certainly not sustainable.

                                          I appreciate your stance but it reflects an Ivory Tower approach to software development workflows (forgive the term) which is generally both infeasible and actually incorrect in the world of market-driven organizations. That’s the context I speak from and the unambiguous position I’ve come to after close to 20 years’ experience in the space, working myself in a wide spectrum of companies and consulting in exactly these topics for ~100 orgs at this point.

                                          It’s incorrect in the world of market-driver organizations only because there’s a massive gap between the technical ability of the consumers of these technologies and the producers, so much so that it’s infeasible to expect a consumer of these technologies to be able to see them for the trash they are. But I think that this is not “correct” it’s just “exploitative”. Exploitative of the lack of technical skill and understanding of the average consumer of these technologies.

                                          I don’t think the “correct” response is “do it because everyone else is”. It certainly seems unethical to me.

                                          That being said, you are talking about this from a business point of view not an open source point of view. At least until open source got hijacked by big companies, it used to be about small scale development by dedicated developers interested in making things good for the sake of being good and not for the sake of a bottom line. This is why for the most part my linux system can “just update” and continue working, because dedicated volunteers ensure it works.

                                          Certainly I don’t expect companies to care about this kind of thing. But if you’re talking about solely the core open source world, “it’s infeasible in this market” isn’t really an argument.

                                          Google has to work this way because their codebase is so pathological they have no other choice. Many small orgs, or orgs decoupled from typical market dynamics, can work this way because they have the wiggle room, so to speak. They are the exceptions.

                                          I honestly don’t like or care about google or know how they work internally. I also don’t like go’s absolutely inane idea that it’s sensible to “depend” on a github hosted module and download it during a build. There’s lots of things wrong with google and go but I think that this versioning approach has been a breath of fresh air which suggests that maybe just maybe things may be changing for the better. I would never have imagined google (one of the worst companies for racing to the bottom) to be the company to propose this idea but it’s not a bad idea.

                                          1. 2

                                            The fact that everyone including end users has become used to the pathological complacency of modern software development is…

                                            …reality. I appreciate your stance, but it’s unrealistic.

                                    1. 2

                                      I don’t get what flexibility offers dynamic types?

                                      1. 7

                                        One issue: Type Checking vs. Metaprogramming; ML vs. Lisp. These features are at odds: dynamically typed languages let you write shorter programs because you can “compress” the code via metaprogramming. All other things being equal, shorter programs are more correct.

                                        That post is from 2016 but it’s come up a lot in Oil since then. Oil is now statically typed (with MyPy) for speed, not correctness. (Some color on that.). Static types are great for predictable speed (the kind of speed I want).

                                        The same issue comes up in Rust vs. Zig – Rust favors static typing while Zig favors metaprogramming (even though both languages have some of both). Comment on that, and the whole thread is good.

                                        It’s a tradeoff; some problem domains favor one or the other. In distributed systems, you deal with data from the network a lot. The more you are interacting with “the world” vs operating on your own models, the more of a tax static typing becomes.

                                        The Rust vs. Zig example is also about interacting with the world (pins on an embedded chip), not models you constructed in your head. My motto is that when models and reality collide, reality wins :) The map isn’t the territory. Static typing is a map that often helps (or doesn’t help) reason about dynamic (runtime) behavior – that’s it. The runtime behavior is what you care about, but sometimes people forget this and let the tail wag the dog.

                                        Thread on that: https://old.reddit.com/r/ProgrammingLanguages/comments/nqm6rf/on_the_merits_of_low_hanging_fruit/h0cqvuy/

                                        where I reference: https://twitter.com/jeanqasaur/status/1394804946818650115

                                        edit: I was thinking about writing a post about other examples of the “world”:

                                        • R: “the world” you don’t control is messy data. You have to clean it and transform it BEFORE it fits some model. The entire ingestion and cleaning process often exceeds the analysis in terms of code volume by 10x. So that’s why the dynamic language “won”. Though speed is a huge problem here – Julia is a dynamically typed language with a novel compilation model that addresses this problem.
                                        • PHP: “the world” is basically people and policies. It’s not a surprise that Wikipedia was written in PHP. The whole thing is a miracle of coordination, incentives, etc. and requires a ton of evolved software to solve. You can’t model this up front. Ditto with all the communities that evolved around forked/customized PHP forum software.
                                        • Shell: “the world” is the Unix kernel, and everything that lives on the other side of it (disks, networks, devices). Trying to make this fit a particular type system is folly; the kernel already has its own model. You can probably find really long-winded static wrappers for kernel APIs that don’t actually make your program any better. (Often what I do is write typed application-specific wrappers, i.e. “role interfaces”, and that approach works better IME.)

                                        But I will probably leave it at this comment since it’s better to actually build Oil than write blog posts about static vs. dynamic typing :)

                                        1. 3

                                          Can you elaborate more on how PHP as a technology was instrumental in Wikipedia’s development? This is the first I’ve heard of this.

                                          1. 2

                                            Hm I don’t have anything all that concrete, but it’s just an observation from years (decades) of using social software written in PHP.

                                            There are multiple related arguments about language design and apps, and I probably can’t tease them apart in this space, but it is basically that R, PHP, and shell are more like “end user programming” or “non-programmer programming” – and moreover programmers actually end up using a lot of this software!

                                            It is a huge amount of irreducible domain logic. It’s better if the people who actually understand the domain write the code, and that is borne out by what we actually use in the real world. (social software like wikipedia with lots arguments, policies, and moderation; R code written by statisticians and not translated by programmers; distros full of shell, etc.)

                                            UIs are like that (as opposed to systems software), and it seems clear to me that social software is like that. One example is all the recent kerfuffle around lobste.rs moderation. There are lots of rules you have to encode in software, and if you do it wrong, the community can fail.

                                            I think a long time ago I was probably influenecd ideas from Joel Spolsky and Clay Shirky. I googled and found these links, although I don’t know if they are making precisely the same argument.




                                            My claim is that this kind of software is necessarily evolved, because at the beginning you don’t even have the people yet. And code in dynamic languages evolve more gracefully, and moreover it’s accessible to domain experts who iteratively respond to “the world”.

                                            I think the creator of Elm did a talk on this, but I don’t think he ever “shipped” his ideas, while PHP programmers are constantly shipping because they edit on the server :) (this is some what tongue-in-cheek)

                                            Here is a good “contrarian” view about dynamic languages from a PL researcher, just rewatched this:


                                            Very nice presentation by a HHVM creator that makes a good argument for PHP:



                                            1. 1

                                              To answer the wikipedia question more directly, I guess my claim is that the “default” is for communities to fail, and Wikipedia has not failed for nearly 20 years straight. That’s a huge feat and it requires a ton of software – nearly all of which is cobbled together in PHP on demand, as far as I can tell (e.g. all the bots that implement content policies, which are kind of semi-automated, etc.).

                                              If you’re trying to model this up front, I think it’s missing the point. Maybe someone will prove me wrong, but so far I don’t see many counterexamples. Maybe StackOverflow is one because that’s a huge site built around logic in C#. I’m not really sure of the details though; I think it’s more of a “site” developed by a company than a self-organizing “community”.

                                          2. 3

                                            For any type system, there are correct programs rejected by the type system.

                                            1. 3

                                              On the other hand, dynamically typed programming is actually just programming with a single type and a lot of partial functions… In practice, this means you can get back most of that metaprogramming back in a typed language, by selectively dropping types in favor of runtime checks, but the reverse isn’t necessarily possible in a “less typed” language. Put differently, in practical statically typed programming, there’s always a way to tell the type system “yeah, that’s not gonna happen, just error out if it somehow does”, which allows you to still express that correct but rejected program.

                                          1. 12

                                            Operator overloading is interesting to me in that it demonstrates how much the programming culture around a language can affect whether the language’s features turn out well in practice.

                                            No statistics to back this up, but I think a lot of people who recoil in horror at the prospect of operator overloading probably arrived at that opinion after working with C++ code. Operator overloading seems to be widely thought of as abused in idiomatic C++.

                                            But other languages have operator overloading too and their idioms have evolved to use it more sparingly. To take the article’s specific example: Kotlin on JVM overloads the + and * operators for the Java BigDecimal class. Idiomatic Kotlin code adds and multiplies BigDecimals using those operators just like the author wants to do. But I have yet to run across any Kotlin code that, say, overloads bit-shift operators to perform I/O operations. Nothing in the language prevents you from doing that kind of thing if you choose, but it’s not considered good style by the community.

                                            Of course, as a language designer you’re rolling the dice to some extent. You can’t know if your language’s community will take some new language feature and run with it in a horrible direction. My point is mostly just that it’s not a given that things like operator overloading will be commonly abused just because they can be.

                                            1. 5

                                              The answer to this might be as simple as whether you overload operators by name (e.g. the “inc” method) or by symbol (operator ++(..)). The former discourages you from changing the operation’s semantics.

                                              1. 2

                                                I think this is one of C++’s biggest issues.

                                                In my opinion, you should provide the language with information about how to do something — this is how you add two of this type together, this is how you move this type, this is how you copy this type, this is how you dereference this type — and the language should decide when to do those things. But instead, you tell the language what should happen when the + operator is used, that should happen when the -> operator is used, when the * operator is used, you provide the T(&&T) constructor and the T(const &T) constructor and the =(&&T) operator and the =(const &T) operator.

                                                Not only does this result in a lot of boilerplate (two ways to move, two ways to copy, two ways to add, two special ways to add 1, two ways to subtract, two ways to subtract 1, ….); it also encourages operator overloading abuse because you’re overloading operators and not semantics.

                                                Who said using “<<“ for writing to a stream is wrong? You’re just overloading the symbols “<<“; nothing is suggesting that “<<“ should be any kind of left shift. (Except that the precedence rules for “<<“ as a stream write operator are completely bonkers.)

                                                1. 3

                                                  It’s worth noting that there are sometimes cases where you want to define ++ and not + (for example, ++ on an object representing a date would mean ‘the next date’, but you can’t sensibly add dates) or + but not ++ (matrices, vectors).

                                                  1. 2

                                                    I think that’s more a matter of wanting to define + on a Date only if the right hand side is an integer and not a date, ++ meaning +1. C++ does this kind of overloading very “well”.

                                              2. 3

                                                Operator overloading is one of those features that is not intrinsically evil, but which doesn’t compose well with some others. In particular, it really doesn’t play well with operator precedence. a + b * c as an arithmetic expression may make sense to execute as a + (b * c) because that’s how people are taught arithmetic, but what if a and b are strings, operator+ on string means concatenate, c is an integer and operator* on string and integer is repeat? Should "foo" + "bar" * 2 evaluate to "foobarfoobar" or "foobarbar"? The latter is consistent with arithmetic, but is probably surprising to a lot of readers who know the types and don’t think of the + and * as related.

                                                In Verona, we are supporting operator overloading (and any word or symbol can be an infix operator) but not precedence. Any sequence of the same operator is applied left to right. Any sequence of different operators is a parse error and requires explicit brackets.

                                                1. 2

                                                  I don’t know for sure, but I suspect the opposite is true: language features determine the culture. There are different ways to implement operator overloading, and they lead to different results.

                                                  One of the core design tenants of C++ is that user-defined types should do everything that a built in types do. Hence, it’s operator overloading supports everything. You can overload ,, ->, =, and implicit conversions.

                                                  In Scala and Haskell, one of the goals is to be able to “write abstract math”, so there you can define your own custom operators (and even custom precedence, in Haskell).

                                                  In Kotlin and (to a lesser extent) Python, operator overloading is very tame and scoped only to overload enough syntax to make BigInt and the like work.

                                                  But I have yet to run across any Kotlin code that, say, overloads bit-shift operators to perform I/O operations.

                                                  Counter-example: a bunch of pre-Compose UI frameworks which didn’t have access to compiler plugins overrode unary plus or call without parameters to mean “add the current thing to the enclosing UI container”.

                                                  1. 1

                                                    I think Rust got it right in this respect - have just a bunch of overloadable operators represented by traits covering the basic arithmetic operators that would help reduce boilerplate (as in the case of Java’s BigInteger and BigDecimal classes), but not unbridled overloading like in C++.

                                                  1. 45

                                                    Let’s see. I’ve:

                                                    • brought down credit card processing for a national retailer
                                                    • cut off all Internet access to a major United States military installation (twice!)
                                                    • helped bring down an entire automobile manufacturing facility
                                                    • helped break all internet access via cell phone for one of the major US cell networks
                                                    • shipped incorrectly optimized code that caused the (important, air-gapped) system to become accidentally quadratic

                                                    So, you know. Be careful.

                                                    1. 21

                                                      I can relate to this, though I wouldn’t say I’m on the same level as you, there’s for me a long way to go. Two of my most significant achievements:

                                                      • Brought down the debit card processing for a multinational bank issuer (only on one country sadly, and just for 2 hours).
                                                      • Deleted the entire payment records database for a local private university on a semester, nobody noticed it, and I managed to restore it using the only backup in existence: an Excel sheet I was using to verify data.
                                                      1. 9

                                                        I managed to restore it using the only backup in existence: an Excel sheet I was using to verify data.

                                                        Deeply in awe right now.

                                                        1. 7

                                                          To make things more exciting, that Excel file was just in memory, so a complete computer crash would have left me helpless. I learnt my lesson and do double checks on data edition, it is funny now how I make sure about doing things right even when I’m just changing a value for parameter on a file.

                                                      2. 14

                                                        Sounds like you’ve had a productive and interesting career, then!

                                                        1. 15

                                                          plot twist: he’s an intern

                                                        2. 5

                                                          Did you face hard consequences

                                                          1. 15

                                                            brought down credit card processing for a national retailer

                                                            No. I fixed it before it became a problem and explained to the rest of my team what had happened.

                                                            cut off all Internet access to a major United States military installation (twice!)

                                                            First time: no, because they installed the update without testing it in their environment first. Resulted in a lot of paperwork on their end, though.

                                                            Second time: whoo boy. I had written the compiler that turned network intrusion signatures into code that could run on our devices. I messed up the code generator for one part, so that in certain rare circumstances, an and would be an or…which meant that certain signatures would suddenly start matching just about everything. Some customers had it set up that certain signature matches would result in blocked traffic. You can see where this is headed.

                                                            The compiler had actually been pretty extensively tested, but the problem manifested on an older configuration that didn’t have a device still in our testing pool (I know, I know).

                                                            I had to spend a couple of days doing non-stop calls with my boss to various impacted customers, apologizing, answering their questions, and basically (and deservedly) eating crow.

                                                            helped bring down an entire automobile manufacturing facility

                                                            helped break all internet access via cell phone for one of the major US cell networks

                                                            These two ended up being a lot of noise and phone calls but, ultimately, the customer had deployed stuff into their environment without testing it first. The issues on our side were from being too aggressive with what we defined as “malicious network traffic”.

                                                            shipped incorrectly optimized code that caused the (important, air-gapped) system to become accidentally quadratic

                                                            Not from the customer or my company, no, but from myself, very much so. I just about had a nervous breakdown, seriously. It got bad enough that I had resolved to quit as soon as I figured out what the problem was (I certainly wasn’t going to quit and leave the problem for someone else), and had convinced myself that I was just terrible at my job and had been faking it all these years. I was miserable, working long hours every night for weeks trying to figure out the problem, constantly preoccupied, not enjoying time with my family.

                                                            Finally figured out the problem, got the fix in, and ended up staying and being reassured that I didn’t suck, which was nice.

                                                            (Moral of this last story, database query optimizers can sometimes make the wrong decision so don’t assume that the solutions they pick in your test environment are the ones they’re going to pick in the field…)

                                                            I actually got a job offer during that time from what might have been my dream job. I turned it down because I didn’t want to leave my current company in a bad state. I don’t know if I made the right decision, but I’m happy, so I suppose that all worked out…

                                                            1. 2

                                                              Thanks for sharing.

                                                        1. 5

                                                          At first I thought, “great, another todo app”, but this one is actually really cool. +1

                                                          1. 1

                                                            Thank you so much :D

                                                          1. 16

                                                            For another perspective, I suggest you read “Bullshit Jobs”. It speaks a lot about the logics of big schizofrenic corporations and the psicology behind middle management. It also speaks about the rise of “managerial feudalism” and how this reflects on everyday life inside a corporation.

                                                            1. 7

                                                              Good book rec. This whole piece is kind of deluding itself about what a corporation is and does.

                                                              Maybe one of your organizational values is “do what your boss says.”

                                                              I read this, and I was like, that’s every company! What company doesn’t have this value!

                                                              1. 4

                                                                A cooperative, because there are no bosses.

                                                                1. 4

                                                                  Worker led companies are not nearly as pitiless. In many cooperatives though there are still seniority ranks, there is still a managerial role, and the “boss” becomes distributed over the whole of the workers, so there is still some dictatorial aspect in the end.

                                                                  1. 3

                                                                    No authority doesn’t mean no law and no hierarchy. It just means that the law and hierarchy derives from the workers and not from one person or from the state. and they can be changed through voting. Then yes, there are cases of cooperatives, especially very big ones with thousands of employees, where this mechanism becomes a ritualized appendage that doesn’t challenge who controls the cooperative but they are exceptions, not the rule.

                                                                2. 2

                                                                  Companies where the boss first asks their employees what they think should be done and then based on their advice says: “sounds good, let’s do it like that”. Yes, in some sense they’re still “doing what their boss says”, but “do what your boss says” strongly implies that the boss decides what the employee should do without them having much input in it.

                                                                  I wouldn’t work anywhere where I would just be doing ‘what the boss says’.

                                                                  1. 2

                                                                    Eh? It’s my boss’ job to go to meetings I don’t wanna go to, and to let me know where we’re going. It’s my job how to get there.

                                                                    1. 1

                                                                      What company doesn’t have this value!

                                                                      You used an exclamation point instead of a question mark, but I think that is a great question!
                                                                      I had to spend most of a day thinking about it off-and-on before I felt prepared to try and offer an answer, so thank you for prompting these thoughts.

                                                                      When I read “do what your boss says” as an organizational value, I find a lot to unpack in the phrase. Much of it goes beyond merely acknowledging a difference in power or authority. I cannot read the author’s mind to know if this is what they meant, but when interpreting the phrase “do what your boss says” as a value, if it begins and ends with those five words, then that interpretation is missing out on an entire layer of lived reality.

                                                                      Consider the differences between:

                                                                      • “Do what your boss says, do only what your boss says, and nothing more.”
                                                                      • “Do what your boss says, and be mindful of ways to make it better.”

                                                                      And these two:

                                                                      • “Do what your boss says, do not question or alert anyone, even if you see a problem.”
                                                                      • “Do what your boss says, and raise questions when you see a problem.”

                                                                      If none of those seem different to a person, or if they have never had separate experiences that shine a spotlight on those differences, I can understand them not examining further. Yet each is a world of difference. Even in benign office workplaces, it can wind up being a matter of life or death in ways that seem insane at first glance, but which ultimately can be traced back to culture. The story is a bit too long to shove in this (already-long) comment, but there was a situation where a pregnant woman at an office job almost died in her chair from a culture of “brag about good news to your boss, but bad news never flows up.” So I am not over-dramatizing this world of difference.

                                                                      I spent years dismissing the whole “culture is everything” and “values matter, but are hard to change” aspect of organizations (whether corporate, governmental, community, or otherwise). Especially when it came to corporations, I had an inescapably cynical, instrumentalist view about what a corporation is and does, as you worded it. Though perhaps I was more pessimistic than you are.

                                                                      My mind was only changed after two things happened.

                                                                      First, I came across a definition of culture that was infinitely better than all of the pie-in-the-sky, mando-fun teambuilding, platitude parade bullshit that I had long associated with it.

                                                                      Second, I observed and experienced differences in outcomes that I could not attribute to anything other than problems of culture. I tried to find anything else. Process deficiencies, technology choices, even matters of power and authority, all are more tangible (and therefore felt safer to engage with) than those squishy culture-and-values questions.

                                                                      The definition I came across was this:

                                                                      “Culture is the framework by which people in an organization will make decisions.”

                                                                      I do not believe that was the exact quote, but it is close. In a corporate structure of knowledge workers, absent from but implicit in that phrase, is probably “when there is no established process”. Yet perhaps not? Even that notion, of how often, in what cases, to go around or outside of a process, is one-hundred-percent within the realm of a cultural value.

                                                                      Now this does not mean I am pollyannaish about organizational culture and values in all cases, or at all times.

                                                                      There are going to be middle management MBA-types who crow about “culture” blindly, because they have learned that this is the pavlovian trick that gets them the treat: respect among peers, a high salary, and so forth. If a bad actor in a position of authority is especially good at hiding their motivations or incompetence, I do not have a magic wand to wave that can solve that problem systemically. However, I no longer let my cynicism about how other people engage with questions of culture keep me from engaging with those questions in a manner that is productive and empowering.

                                                                  1. 5

                                                                    Corporate structure is a replication of feudal structure where the board of directors delegate oversight to lower and lower levels of company “nobility”, and everyone gets to set their own renumeration. From a bottom up perspective they’re not necessary for production at all, but from capital’s perspective executives are the obviously rational way to defend their property interests.

                                                                    In short, they don’t do anything except for defend profit and extract surplus.

                                                                    1. 4

                                                                      At least unlike nobility of centuries past, or even the dynastic capitalists of 100 years ago, executives are required to work, to such an extent that you hear them engaging in the same “Gosh I’m so busy” virtue signaling of working all the time.

                                                                      The idle rich still exist, but it is not the executive described here. Labor exploitation has moved up the ladder and you have corporate leaders missing their kid’s birthday party to work on the weekends, the same as an aspirational middle class worker picking up an extra shift.

                                                                      I forget where I read this, or I would share, because it surprised me, but the percentage of people who are in the 1% that get the majority of their wealth from income/salary is higher than it’s ever been. Now that’s percentage of people in that percentile, not percentage of combined raw wealth in that percentile, but fascinating nonetheless.

                                                                      1. 1

                                                                        I agree, but can you offer an alternative? I happen to be involved in a political party and it’s a hard problem just to set up reasonable vetting of newcomers. You get all kinds of applicants ranging from math nerds who love trains to paranoid crackpots who notify police that your WiFi is reading their thoughts. Some are latent Nazis, others radical anarchists. Propose a framework to vet and integrate newcomers, please.

                                                                        1. 3

                                                                          Not sure what this has to do with company execs, but engaging with it anyway:

                                                                          Send them a letter describing how your meetings work and the expectations on members.

                                                                          Then invite them to meetings as a prospective member and ratify their membership after N meetings if you want to keep them in the group?

                                                                          The political party I am a member of has a simpler system: I think it just accepts members unless a cursory search of public records shows bad behaviour.

                                                                          There’s a complaints process for removing members that are problematic. Complaints process overseen by representatives elected by members.

                                                                          1. 1

                                                                            Complaints process overseen by representatives elected by members.

                                                                            Hierarchy. And since they are elected, they have a higher chance to get re-elected.

                                                                            They can also throw out people who oppose them and keep their supporters, thus solidifying their position even more.

                                                                            Does your party happen to have a rule-making committee (perhaps with a delegate system)? Commies had (or have) one (both Soviet and Chinese). Then they elected a subcommittee (called Politburo) to hold the power in-between the sessions which eventually gained enough support in the central committee to mandate that they will pre-select central commission candidates. That’s how a nice democratic party becomes a top-down evil corporation. (It helps that a member of politburo is a minister of interior.)

                                                                            I mean, it’s hard for me to imagine systems that operate in non-hierarchic ways. But the problems with hierarchy are real and are independent of organization type.

                                                                            1. 2

                                                                              Rules can be changed by assemblies of delegates at different levels, yes.

                                                                              If you want to avoid traditional delegate systems then you can use sortition (select executive randomly from membership like jury service).

                                                                              If you want to avoid hierarchy entirely then you need anarchist theories, I think.

                                                                              I think traditional delegate systems can maybe work OK so long as the electorate is informed and the electoral system is expressive and fair enough. Israel has a good democracy by those measures, apparently, but I don’t know how well the Israeli state is considered to be serving its people.

                                                                          2. 2

                                                                            I agree, but can you offer an alternative?

                                                                            The corporate structure is pretty dictatorial, and there are alternatives to that even in today’s society, like with the government. Suppose company executives were elected by and can be recalled by the population of the company, or perhaps there was some kind of representative oversight council that had to ratify executive decisions (think like the US Senate approving of the president’s appointees), but otherwise did basically the same job they have now.

                                                                            Obviously, as we see in government, this is still far from a perfect system.. but it more-or-less works and people are already familiar with the concept so it might be an easy baby step to consider.

                                                                          3. 1

                                                                            who are the share holders in this analogy?

                                                                            1. 2

                                                                              The mass of shareholders forms an abstract capitalist which is the monarchy at the top of the feudal hierarchy. The shareholders (of which the board is some portion) have absolute sovereignty over production.

                                                                              1. 2

                                                                                That’s incorrect, though. Most of the big ones are cartes of cartels with interlocking boards of scheming people backing corrupt laws that benefit their own class, specifically them, at everyone else’s expense, including shareholders. The leaked memos from Citigroup called the new structure a “plutonomy.” Just a new form of plutocracy where they keep their control in executive positions, the boards, paid-for politicians, and infiltrated regulators (esp Goldman).

                                                                                If really working for shareholders, the folks in this class would’ve sent them the vast majority of the wealth instead of extracted it for themselves with shareholders holding a mix of real money and IOU’s that can change in an instant. If for stakeholders, the employees and customers would get treated better, too. They haven’t been about either in most cases.

                                                                                That’s why there’s a new push for public-benefit companies, foundations, and other structures with incentives that might fix some of this.

                                                                                1. 1

                                                                                  It’s an interesting way to model the corporate structure.

                                                                            1. 8

                                                                              I’m still unconvinced contracts need to be strictly separate from interfaces. The argument that enforcing operators would be repetitive maybe falls flat on me because it seems trivial to ship the stdlib with some basic Operatable interfaces you can reach for, but also that doing a bit of extra typing for clarity I’ve generally seen as part of the golang ethos.

                                                                              Similarly, the idea that you can never have discrete instances of contracts (versus interfaces) runs counter to how I’ve used generics in the past where generic constraints are just interfaces and you can reference the type constraint interface when declaring values later.

                                                                              1. 6

                                                                                Agreed on interface reuse. My guess is adding new semantics to interface is hard to back out of, where as “contracts” can just ultimately be deprecated when the dictators decide that the experiment “failed.”

                                                                                OK, maybe that’s not fair. But, I agree that there’s a weird resistance to extend something that seems to really make sense, in favor of adding something completely new. Either way, 3rd party tooling will be broken until updated…

                                                                                1. 2

                                                                                  They extended functions and types to accept type parameters, but then they neglected to do the obvious thing which is extend interfaces with type parameters. Do that, then allow interfaces to be the specifiers in the type parameters list - done. They dedicated a whole section to this but every argument is unconvincing and evinces a lack of imagination. Just read this:

                                                                                  Contracts, unlike interfaces, support multiple types, including describing ways that the types refer to each other.

                                                                                  Then add type parameters to the interfaces.

                                                                                  It is unclear how to represent operators using interface methods.

                                                                                  Other languages either map operators to a special name or provide a syntax for the overloading. Most design documents have a prior art section - do your homework!

                                                                                  An interface is a type, not a relationship between function definitions and callers. A program can have a value of an interface type, but it makes no sense to speak of a value of a contract type.

                                                                                  Again, there is no creativity here or an attempt to see what other people have done. Expand the definition of interface. I would solve the problem like this: if an interface appears in a type parameter list, the type is unboxed and preserves its type, whereas if it occurs in a parameter list as a type, then it is the usual boxed interface. It is really that simple. This also happens to be nearly exactly what Rust did for a long time.

                                                                                  In other words, contracts are not extensions of interface types.

                                                                                  This is wrong. It’s wrong, it’s wrong, it’s wrong.

                                                                                  I will end this comment with just a little bit of polemic, which by now is par for most comments about Go but totally deserved: I do not trust the language designers. There is too much NIH syndrome, too much anti-intellectualism, too much reinvention of solved problems. It is a waste of a great runtime. Use something else.

                                                                                  1. 7

                                                                                    do your homework!

                                                                                    It seems manifestly obvious that they did, considering the design document cites numerous languages and how their design improves on past mistakes. Consider cutting back on your hyperbolic ranting and snobbery; it undermines your commentary.

                                                                                    1. 2

                                                                                      That comment was specifically about the preceding quotation.

                                                                                    2. 2

                                                                                      They extended functions and types to accept type parameters, but then they neglected to . . . extend interfaces with type parameters.

                                                                                      Although the draft doesn’t explicitly mention interfaces as a possible parameterized type, I don’t see anything that would imply they aren’t supported.

                                                                                  1. 29

                                                                                    As much as I believe every single last person involved in cryptography yelling “use Signal”, it doesn’t fit everyone’s use case of a chat application.

                                                                                    Signal has a hard requirement that you give them a mobile phone number to tie to an account and register from a smartphone. This number is also exposed to other contacts. As for the alternatives in the article, namely: Wire has monthly fees that may prove difficult to pay anonymously. WhatsApp is owned by Facebook; even if you consider this okay enough somehow, that still requires you to go through your smartphone, on which it requires a phone number for registration; not that you could install it on an OS that isn’t macOS or Windows anyway.

                                                                                    People may suggest to “just get a burner SIM”. But that is not a reasonable option if your goal is to hide your real life identity: For example, in Greece and Spain, you must provide ID and formerly anonymous SIM cards were blocked see COM(2010) 253, p. 69. That’s a non-starter in these scenarios. Of course, you may still argue that people that need to go to such extents to hide are almost certainly criminals, terrorists or dissenters (none of which may be worth protecting depending on your morals), and you’d probably be right. Nonetheless, the increasing disappearance of an untied, non-real-life identity scenario is a worrying prospect to me.

                                                                                      1. 5

                                                                                        Read to the end of the article, where Signal clarifies that they don’t consider it a problem because the goal was never for Signal Desktop to provide at-rest encryption. (I will say however that I too have always wondered why they bothered using SQLCipher to begin with.) If you need that, use full-disk encryption. That will protect you much better.

                                                                                        “But they should be aiming for at-rest encryption.” Let’s play this out:

                                                                                        1. The only way Signal Desktop can accomplish this without some additional support from the platform*, AFAICT, is to require a decryption password that the user types in at startup. Already this breaks a lot of useful things: it breaks the ability for the app to autostart when the user logs in, and that means that if the user forgets to type in the password (and they will) notifications for new messages won’t work, silently. So already we’ve seriously broken the UX.
                                                                                        2. The decryption password can’t even be secured properly. A malicious app on your system can just sniff the keystrokes. Or, it can just record the screen. AFAIK Windows and macOS don’t restrict these operations by default (maybe keylogging, but I’ve never gotten a prompt or anything for screen recording IIRC). Wayland on Linux is supposed to fix this but adoption is “in progress” at best on that front so that doesn’t do us any good.
                                                                                        3. Let’s say that isn’t a problem. Maybe something changed since I used Windows or macOS and they’re better now. The password still isn’t secure. Your disk isn’t encrypted so the attacker can tamper with the Signal binary if they have physical access. Now Signal is malicious. Game over.
                                                                                        4. But let’s say that the attacker doesn’t have physical access, and you’re sure all the apps on your system are trustworthy. Are you sure they don’t have a security vulnerability and won’t get compromised to sniff your Signal password?

                                                                                        The list goes on. This can’t be mitigated at the app level because the platform is fundamentally not designed for this. Mobile devices isolate apps by default; you don’t routinely run processes that aren’t sandboxed. But on desktop, the opposite is true. There are valiant efforts to sandbox apps, like the Mac App Store requiring that all apps distributed through it enable sandboxing, and Flatpak on Linux. But those are still opt-in. Are you sure that everything on your system is sandboxed enough? To actually guarantee this, you need something like Qubes.

                                                                                        Signal Desktop absolutely has problems… but I don’t think this is one.

                                                                                        [*]: keyrings have this same problem. Usually they’re unlocked automatically on login, so any unsandboxed app running in the user’s session can just ask the keyring to give it the Signal password. At least AFAICT… I vaguely recall macOS having some sort of access control.

                                                                                        1. 2

                                                                                          The core premise of the article is completely mistaken. The database key was never intended to be a secret. At-rest encryption is not something that Signal Desktop is currently trying to provide or has ever claimed to provide. Full-disk encryption can be enabled at the OS level on most desktop platforms.

                                                                                        2. 9

                                                                                          I definitely agree that, when possible, people should avoid communication tools that require phone numbers and use something like XMPP with OMEMO instead.

                                                                                          If you do need/want to use Signal or similar, there are phone number options that let you maintain anonymity. For example, https://jmp.chat/ gives you a Canadian or US number without requiring any identifying information (you can even signup over Tor). If you want to keep the number past 30 days, you can pay in Bitcoin Cash or Bitcoin, or use https://shapeshift.io/ to pay with other more anonymous cryptocurrencies.

                                                                                          1. 8

                                                                                            Yep. I use Signal extensively in my labor activism. This is an example of an activity which is entirely legal in the United States, but where I am putting people in danger simply by talking to them. I agree 100% with all your criticisms, and it’s quite unfortunate that there are many situations in which there isn’t a realistic alternative.

                                                                                            1. 2

                                                                                              Is there at least groundwork for such an alternative to Signal that doesn’t require a phone number? I’m in the same situation.

                                                                                              1. 1

                                                                                                The protocol is open, although it’s my understanding somebody would need to do a lot of implementation. I’d also suggest that future work should be based around expecting users to explicitly manage their keys, rather than trying to abstract that away.

                                                                                                1. 2

                                                                                                  I’d also suggest that future work should be based around expecting users to explicitly manage their keys

                                                                                                  Why? To me this is the main selling point of Signal. And from my observations teaching PGP (long ago), key management is one of its biggest downfalls.

                                                                                                  1. 1

                                                                                                    Sure. It’s because the automatic management both introduces insecurities, and makes it so that good key-verification practices are more friction than sloppy practices.

                                                                                                    The most significant insecurity is that anyone with control over your phone number can gain control of your account. A stolen SIM or a number-porting attack could both be used that way. They won’t see message history, but they’ll be able to impersonate you. The only defense against this is that there’s a small notice in each chat about the safety number being reset.

                                                                                                    The point about safety numbers dovetails with my larger point about good practices being hard. When you’re scaling up a large organization, educating everybody about what the safety number means and how to verify it is a constant undertaking. Meanwhile, people are constantly replacing their devices, accidentally reinstalling the app, intentionally reinstalling the app, etc for a variety of reasons. It’s constant tedium, and if you just punt on doing the work, there’s a chance of an impersonation attack being successful.

                                                                                                    What I would like is to put key management front and center, so that everybody gets the message that this is something they should be paying attention to and learning more about. I’m envisioning, for example, a first-start wizard that walks users through creating an offline key and using it to sign a per-device subkey, with alternatives also presented if they want to add a key some other way. Yes, it’s a lot of work which would slow down adoption immensely. Thus, I don’t realistically expect any for-profit entity to be the first to offer a product that works this way. Still, in my ideal world, it’s what I’d like to see.

                                                                                                    1. 1

                                                                                                      Hm. So if I can rephrase this position, basically you’re saying that good practices (i.e. verifying safety numbers) isn’t on a level playing field with unsafe practices, because it’s much easier to do the latter. And basically you want to level the playing field by making both take equal amounts of effort? Did I get that (somewhat) right?

                                                                                                      1. 1

                                                                                                        I think that’s right, yes. I know it’s in some ways a quixotic idea.

                                                                                            2. 6

                                                                                              I use Signal constantly, but this is a sound comment and still only covers maybe half the serious concerns I have with Signal.

                                                                                              1. 2

                                                                                                We are pseudonymous in Peergos (no phone number or even email required to sign up). At the moment we are focussed on storage and sharing, but we plan to implement a group chat/messaging solution using Messaging Layer Security once it stabilises.

                                                                                              1. 2
                                                                                                • etcetera
                                                                                                • lib like bib
                                                                                                • char like far
                                                                                                • I read fsck like the f-word
                                                                                                • skeemuh, schema is already plural
                                                                                                1. 3

                                                                                                  This is a bit of a random bump but I just loaded a common lisp library that was last updated in the year 1990 (“series”, which nearly made it into the language spec). It still works. When’s the last time you used a library from thirty years ago and it worked?

                                                                                                  1. 19

                                                                                                    If you plan on using Lisp well into the future then you should use Common Lisp because you know the language is never going to change and the books written on it (from the 90s, to 2005’s Practical Common Lisp) will always work, as well as the libraries that are available. You will be part of a continuous tradition that started with John McCarthy - many of the best Lisp programmers moved to Common Lisp during the standardization process, whereas Scheme is relatively its own thing (yes, I know who Guy Steele is).

                                                                                                    It is not the prettiest language but I am going to say that, regarding the differences between it and Scheme that people start fights over, you might find as I have that the decisions Common Lisp made were uniformly better across most of those dimensions, including nil vs. false (these should be the same thing!!), and even, the somewhat strange #’f and funcall syntax. For its gargantuan feature list, over time you will grow to like and appreciate the facilities that are available to you and realize that it is, in fact, a very practical language, designed over the decades of experience people had with actually using it for real software. Scheme (and which scheme: RSR5? RSR6?) is a small, small language that the various implementations (chicken, racket, guile) have to foist extensions over just to be practicable. Scheme does not have keyword arguments! Both racket and chicken do, but they use differing syntaxes. Even such a small and useful feature is not standardized and a small taste of the kind of divergence among implementations so if you are ready to be platform locked, go right on ahead.

                                                                                                    Really, the difference between (any) Scheme and Common Lisp is that, after having used both for significant projects, the Scheme community is satisfied with a nice, clean definition of a language, and Common Lisp is the result of satisfying the real needs of people in industry.

                                                                                                    Should you even use Lisp? I don’t know you and I don’t know your goals. But if you are choosing between CL and Scheme the answer is exceedingly clear imo.

                                                                                                    1. 2

                                                                                                      How do you like the concurrency support for CL? I’ve read that it isn’t supported by the standard lib, but most people use Bordeaux threads - are you happy with it? Coming from other languages, it’s a little scary for something as fundamental as concurrency not to be in standard lib.

                                                                                                      1. 8

                                                                                                        Bordeaux-threads might as well be considered the de facto library for system threads. If you’re interested in M:N threading with nonblocking scheduling there are also a plethora of implementations for that, although I haven’t used any personally. Clojure is another Lisp that does this quite well, and that one happens to have it in the standard library (but! I remember when it wasn’t, and Timothy Baldridge released lightweight threading as a codewalking macro. Such is the power of macros, and totally impossible with hygienic ones, I might add).

                                                                                                        As for this standard library business… if it’s ever been needed, someone has written it and published it. I wouldn’t be “scared” that anything is or isn’t in a spec released in 1995, especially something for which the dominant paradigm has shifted so much over the past 15 years. Remember when transactional memory was the next big thing? Pepperidge Farm remembers. And even now, there is a divergence on whether people program in a pseudo-blocking procedural way (go, async await), monad-style promise chaining (all the functional languages, JavaScript before ES16), and whether concurrency was even appropriate in the first place (data parallelism, like Rust’s rayon or beam crates). Why should any standing committee decide to bless any one paradigm over another without literal decades of trial testing testing? For a frozen language like this, people coalesce over time around well written libraries, so don’t worry about that and ask around (IRC, Reddit, Google) if there is a library for this or that.

                                                                                                        1. 4

                                                                                                          I’ve used Bordeaux threads, and they work well enough. But I’m used to 90s-era and earlier languages which don’t come with concurrency baked in. In comparison to those, Lisp is pretty good.

                                                                                                          1. 4

                                                                                                            Would also mention that C didn’t have threads in the standard library until 2011 and it wasn’t seen as big handicap.

                                                                                                            1. 3

                                                                                                              Bordeaux threads is de-facto standard, yeah, but I rarely find myself wanting to do low-level threading (in any language) anymore. There are various libraries built on top of it to provide higher-level concurrency primitives. For example lparallel provides task queues, promises, and parallel versions of map, reduce, sort, etc.