1. 9
    On Types clojure person blog.cleancoder.com

  2. 23

    This is a brief memoir (by Bob Martin) which offers almost nothing in terms of type theory, and only 4 paragraphs are relevant to Clojure

    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.

          3. 1

            Regardless of however you feel about Clojure itself, it’s amazing the devotion it seems to cultivate in its users.

            However, instead of that typing being controlled by the compiler, it is controlled by me. I can enforce simple types, or very complex data relationships. You might think of it as a kind of pre-condition/post-condition language. Eifel programmers would feel very much at home with it. It’s an almost perfect way to engage in Design by Contract.

            Testing still needs to be done, and various testing methods have gotten a lot of excitement, but I find Design by Contract to be a fantastic thinking tool during development. Another great way to engage in Design by Contract (preconditions/postconditions) is out of the box in Ada 2012 since it opens the door for you to use formal verification with SPARK for that module as well. Also, you get range checks and predicates you can write and then attach to subtypes or type invariants that get checked on every assignment and usage as a parameter.

            The big issue with runtime checks and many static type systems is that it they don’t prevent you from mismatches in semantics when assigning (or binding) values and swapping values with similar constraints, like integers or strings is easy. This is where semantic types like “derived types” in Ada or tuple structs in Rust come in handy to help prevent mistakes.