1. 27
  1. 13

    This makes a lot of sense to me; it’s about the impression I would expect to hear given the author’s background. I agree with a lot of the takeaways.

    I had the luxury of learning elm on my own time and on greenfield projects, and haven’t worked on anything truly enormous (biggest project has been a bit over 8k sloc). I also came from a different background, already knowing some Haskell as well as just being familiar with a pretty broad set of languages.

    I do find I end up writing a lot more code for the same logic than I would in Haskell, a lot of which is boilerplate. json encoder/decoder thing is annoying; in haskell you can just do:

    data Foo
        = Bar
        | Baz Int
        | Quux String
        deriving(ToJSON, FromJSON)
    

    …and you’re done. Elm suffers a bit from being both very rigid and aggressively anti-cleverness; to avoid this kind of boilerplate you’d need something a little more than what the language offers you. Right now the best solution is some kind of protobuf-style code generation, which is a bit annoying in that it means more random build system glue. Also the last time I seriously surveyed the ecosystem for this kind of thing I found the results wanting, but it’s been a year or two since I’ve looked, so maybe it’s gotten better.

    Elm makes what I think is a very conscious trade-off, accepting some of these kinds of paper-cuts for larger projects in exchange for an easier learning curve and fewer footguns for folks coming from javascript. It’s not quite what I want from a language; I think there’s a better sweet spot to be had for folks who are willing to learn a couple more advanced concepts in exchange for expressiveness (macros, higher-kinded/higher-ranked types, maybe some others), while maintaining the saftey and not even really making the language terribly complex, but that’s not elm’s target audience (I may be working on a language that tries to hit that…)

    I still reach for Elm when I need to write a simple-ish web UI; it’s not perfect, but it’s really really good as long as you’re using it for it’s own little niche.

    1. 2

      If, after a considerable amount of experience with the language, you realized the only good use-case is for a simple web UI, to me that raises a red flag. Embedding Elm semantics into my brain isn’t worth that.

      1. 8

        If web UIs are not much of what you do, then perhaps, though for me there wasn’t much semantics learning to do coming from Haskell. Though it’s also a good stepping stone towards more generally applicable functional programming; the sad state of the world is that many of those have very poor learning resources. And most of what you’d learn in Elm will translate decently well to OCaml or Haskell or other similar languages.

        But yes, if you’re looking for a tool to do something other than web UIs, Elm is not it. If that is what you are looking for, it is a very good tool.

        1. 1

          Vanilla Javascript suits that use-case just fine though.

    2. 5

      I share most of the sentiments here. About half the time I’ve spent learning Elm thus far has been on trying to find incrementally better ways of DRYing out my code. I’m still not entirely satisfied. “Vertical” is a good word for it.

      I’m not sure what’s up with their VS Code extension. I have yet to encounter discrepancies between Elm Tooling errors and command line compiler errors. One thing that will definitely confuse the compiler is when I try to write several half-thought-out functions at once. If you want the full benefit of the compiler as you code, you have to write your functions one at a time, starting from low order to high. I prefer to think at a high level first and call nonexistent lower order functions I intend to write later so I can keep my train of thought. Unfortunately, I end up living with a lot of angry red pixels and a very confused compiler until I’m completely done, the one benefit being that, if I’ve modeled my types well, it really does work on first compile.

      Elm’s level of rigor in typing strongly influences how I write TypeScript. Though “incremental” typing has no doubt been an ingredient in TypeScript’s mainstream success, upstream dependencies written in JavaScript and given poor quality bolted-on type declaration files give such anemic and faulty guarantees, they’re worse than no guarantees at all. I’ve therefore adopted Elm’s absolutism in that regard and supplement missing or incorrect types in dependencies with my own.

      1. 3

        There are very limited options for saying “I’ll do this part later”… You application has to compile.

        I think there are many good things in Elm, but I do find this a bit frustrating, given that there are tools available to address this for statically typed languages, like typed holes and deferred type errors, that can reduce the amount of friction during development while not compromising on correctness.

        1. 3

          PureScript breaking out to FFI was an easy way to hack around this for now and clean up or upstream later. The best “hacks” in my experience involved things along the lines of using globalThis.Intl, instantiating an Intl formatter in the FFI file with it’s options and then just consuming IntlObj.format as a pure, synchronous function to get quick date/number formats.

          1. 2

            Usually when I write Elm, I start with the types and let the type errors guide me to what I want to achieve. So I guess the workflow is types => base functions => actual usage in update/view. I have a similar workflow in Derw, but it’s actually possible to work around that currently by calling some global function since they aren’t type checked. So you could have

            isNumber: string -> boolean
            isNumber str = 
              globalThis.doNothing
            

            and replace globalThis.doNothing once you’ve figured out what goes there.

            1. 1

              Does Elm not have the equivalent of Haskell’s undefined?

              1. 1

                It has Debug.todo "some message" which you can use similarly. The difference is you can’t use any Debug functions in prod builds. I use them all the time when I’m blocking out my code, and then remove then 1 at a time till I get what I need.