1. 42

  2. 31

    I was sharing a similar idea in a team meeting recently. The examples I brought up:

    1. Rust shepherds you towards its value system which is low memory use, preferring the stack over the heap where possible, minimal copying, and avoidance of data races, things like that. The operational bias is strong. You ask more “how does this program execute?” than you’ve probably done anywhere else. I think it does its job quite well. Nothing is perfect; you can end up writing pretty ugly code. On the other hand, if your priorities match up for a particular project, it fits like a glove.

    2. Haskell shepherds you towards using static measures (type system, macrology, laws, academia/research) to compositionally model domains that ideally make invalid states unrepresentable (deductive bent, but things like e.g. QuickCheck are more stochastic). The denotational bias is strong. You ask more “what does this program mean?” than “how does this program execute?” Nothing is perfect here, too. But when I want bang-for-buck measures, it provides the right balance.

    3. Smalltalk/Lisp shepherd you towards “living” programs. We don’t stop the process and run it from scratch, we migrate the data over as it’s running. If it fails, we fix the bug and resume the code. The time from “I type some code” to “I see the result” is staggeringly smaller than any other language. You don’t need to figure out how you got here; just dump the running image to disk and resume in 5 years. I can go 6 months without restarting Emacs.

    Both Rust and Haskell provide escape hatches (unsafe { } equivalents), and can get very in the weeds with abstractions, and you can write bad code. But fundamentally if you try to capture the spirit of these languages, Rust is capturing execution (performance and resource usage), and Haskell’s core spirit is meaning (how do ideas combine). Other approaches do this better with different investments (model checking C, for example, or Agda/Coq).

    Shepherding is one aspect. Another is opportunity, which I think is what attracts me to languages. It’s “the dream” that the language sells you, that, in reality, isn’t used as often or as comprehensively as you’d like due to time constraints, throw-away projects, other pressures. But if all else is equal, this language gives you the opportunity to do something well that other languages don’t.

    1. 14

      Once again, Alan Perlis said it first:

      A language that doesn’t affect the way you think about programming, is not worth knowing.

      1. 7

        Turing complete configuration languages shepherd you into writing complex logic with them, even though they are usually not particularly good programming environments.

        I think this one works more like: if doing the hard bit at that layer of the system would solve your problem, Turing completeness is fatally tempting.

        (that time I wrote several hundred lines of code in ant. kill me.)

        1. 5

          Completely agree. Programming languages are user interfaced. User interfaces sometimes restrict what you can do but they make some things a lot easier than others. You can still get your work done with a crappy UI, but a good UI makes it easier to do your work well than badly.

          1. 3

            This is a really interesting and useful concept. I would encourage further exploration into the questions: “what should programming languages shepherd us into?” And “Why is shepherding important in the first place?”. The latter question is motivated by the C++ observation (which has analogs for many languages) that everyone should love C++ because it supports everyone’s programming paradigm; the lie is that you don’t love a language because you can write in i your favorite paradigm, but because you don’t have to read/understand/interface-with code written in other paradigms, which profoundly doesn’t hold for C++. Shepherding toward a single paradigm would be tremendously useful for C++, in my opinion.

            1. 4

              It’s not just programming languages, it’s our office layout, the IDEs we choose.

              But language choice is probably in the top two or three. My guess is that our code itself has a vast and profound influence on the way we think both about coding and solving problems. It’s impossible to stick your head inside of code for a long period of time without the code changing you.

              In many, many ways, as much as we’d like to feel differently, our computers program us, not the other way around.

              1. 8

                In many, many ways, as much as we’d like to feel differently, our computers program us, not the other way around.

                Also the ecosystems. Increasingly, I get the sense that I quit ecosystems more than anything else. Ecosystems often are a long-term projection of what the language shepherds you toward. They also reflect the values of the people within the ecosystem, which is usually self-selecting.

                I do think the fashion of tooling that enforces one way vs the other is a bit overwrought at this point, but that’s a separate discussion.

              2. 1

                Yep. I think the goal with programming languages is picking one (or more) to use that shepherd you towards the things you value — that way you feel at home and not fighting the ecosystem. That might be, time to executable that solves the core requirements, correctness, performance, ability to run everywhere, etc. (or a combination).