I've been working on a project, now at http://www.knode.io for quite some time. It went from Rails to an Elixir back end with an Angular 1 frontend, then a brief experiment with an Angular 2 frontend, and finally to an Elm frontend. It is a complex project with JS interop using ports to render (a) mathematical text and (b) Asciidoc. Plus, there is a Latex-to-Html parser-differ-renderer package that I wrote entirely in Elm (2K of code).
I couldn't be happier with Elm in this project. Many major refactors: instead of the usual white-knuckle experience with prior languages/frameworks, it was, like, zen.
I really liked Elm a lot, but the issue for me was that composing components is a shit show. You have to add variants to the root Msg type for every single subpage and have it dispatch to the right update/view functions.
I'm really excited about a project inspired by Elm called Yew but allows you compose components much more naturally and easily.
I really liked Elm a lot, but the issue for me was that composing components is a shit show. You have to add variants to the root Msg type for every single subpage and have it dispatch to the right update/view functions.
Doesn’t that make sense, though?
An app in Elm is some kind of state + messages that change the state. Since the state is usually too big to fit in a single structure, you break it down recursively into progressively smaller substates. These again have some messages that mutate the state.
Now, doesn’t it make sense to send the “child” messages through the parents? You shouldn’t command the children directly, you should always tell the parent to tell the child do this and that. At least in our [Swift, not Elm] app that makes sense, composes well and keeps the model simple to think about.
Not op, so I don't know his/her struggle. My struggle comes maybe from the syntax I'm not used to, but also it always feels like you have to keep the whole message-graph in mind to understand which message comes from where and goes where and needs to contain which data and while that type system helps, it feels like it also makes it more difficult. You cannot just run it and see how far you come, you're code just won't compile. I know, this is a good thing for bug free production code, but exploration is harder (at least for me).
Also the types become really complicated after a while since you wrap everything in some kind of message type. So your parent message contains a child message, containing some data that needs to get passed to the next view. So errors become less readable or helpful. Or I'm doing something wrong, which could very well be because I'm a bloody beginner.
[I]t always feels like you have to keep the whole message-graph in mind
It should be quite the contrary. When you design a piece of the app, the piece should have its state, messages and view code, so it should be perfectly possible to ignore any context, focusing just on the single piece. Just like when writing pure functions, for example.
You cannot just run it and see how far you come, you're code just won't compile.
This is a known initial hurdle with expressive static type systems I think. It gets better quickly and then you won’t be able to go back, feeling existential fear without the compiler watching your back.
So your parent message contains a child message, containing some data that needs to get passed to the next view.
This is getting too particular for me to explain/help/argue directly. In our app, for example, the main app model is either onboarding, home screen or signed out. Then it makes big sense for the main model to accept messages regarding onboarding, home screen or signed-out state. And when it receives a message related to one of its child states, it just delegates it. This makes sense conceptually and is quite natural to follow when reading the code.
I am not an experienced Elm programmer, so maybe I am getting this wrong, but what we have has worked for us well, so far.
When I was a beginner, I found this extremely slow & burdensome. So much boilerplate!
Working in a huge codebase, I don't feel this pain at all.
I wonder if the beginner experience is off. When you add functionality to a huge application, the ease of threading through state is so much easier than just always winging it like I used to.
I built https://bellpluscat.com/ entirely in Elm. It's a database in your browser kinda like a simpler Airtable. It uses Google Drive as it's backend.
Elm let me a single programmer build this in a couple weeks with no runtime issues even after major refactoring to add new features. It was such a pleasure to work on.
Where one sees dogmatism, other may see sticking to principles. Elm is not trying to be everything for everybody. I think that’s a feature. Accepting its strange, perhaps dogmatic ways made me a better programmer, even in other languages.
I maintain long lived applications. Sooner or later we __always__ have a need to call out to the host environment to work around limitations of the compiler/runtime.
Not being able to do so, and the attitudes of the core elm team that prohibit such actions, make elm a non starter for me.
In the end, it may be a showstopper for you, but go is the prodigal child of "my way or the highway", and it's doing just fine in many production environments.
I've been using Elm a few months for a serious project and really like it. That said, I do get the impression there is some drama at the top (among the overlords) and the direction they want (or others want them) to take things.
I'm not even close to being an overlord or contributing anything to the language (just a consumer who has been very happy with how everything's been working so far) so the fact someone like me is even aware this is going on is mildly troubling. Other libraries I'm fairly familiar with (Pandas in Python, React etc) seem to tend towards quietly releasing without all the public drama among contributors.
Not sure whether it's because it's a smaller community or more of the help/documentation is on places like reddit or discourse (where the overlords argue - vs something like stack overflow), or whether everyone involved just needs thicker skin.
Either way, it's only a mild annoyance to me for now and I really like Elm overall. Would encourage anyone interested to check it out.
Definitely some tension, mainly concerning that there is primarily one gatekeeper, Evan, and he is very focused on 0.19, and therefore 0.18 (the current) is getting stale, and a lot of issues are not fixed/ignored.
Problem is, 0.19 has been underway for a looong time, and is still unclear when it'll be done. They also have this weird thing were they are heavily pushing and promoting the language, and when you complain about these kinds of things, you'll often get back a "this is to be expected of such a 'young' language", which seems contradictory to their narrative of "look at all these companies using them in production".
Personally, I quite like a lot of the parts of Elm. A bit too simplistic for my taste type system-wise, but that is also it's great strength when having to onboard/convince new developers or colleagues. That said, I'm waiting on 0.19 before seriously considering Elm any time again.
This is one of the reasons why I chose Purescript for my team's projects. Also it's got a more complete type system, a simpler FFI, and compiles to less javascript.
This is not to say that Elm is bad. O think it's great as a path into FP, and in fact _was_ my path in. But it does limit you in what you can do and learn.
Also, Purescript has this interesting property of being hard to learn (because it is powerful), but dead simple to use (because it compiles to JS). So you only really get stuck on figuring out how to do things in PS, as opposed to how to get PS working, and therefore every time you get unstuck, you have leveled up. So it's hard, but rewarding.
I'm probably off topic by now, but I do think that Purescript in the frontend is a better option for solid application development.
Purescript looks like a great language and if you want to dive into the deep end of typed FP, then it looks like an excellent choice. One reason I went with Elm for our in-house customer support app, was because of the simplicity of the language. It does result in more boilerplate but I don't think the project would have been successful if the learning curve was steeper.
b) "Native JS for me, not for thee". Much like Go gatekeeps generics to the language authors only, Elm restricts native JS access only to the language runtime because devs "might get it wrong"; forcing them to use the ports system, where they have to type the use of even perfectly pure JS code as a side effect.
c) The official package manager forbids the upload of any package that interacts with JS without the blessing of the BDFL.
I'm aware on the tradeoffs of each case, I understand Evan's intentions; but I heavily disagree with them, which is why I don't entertain Elm as an option for production use anymore and would rather go with something like Reason despite being less knowledgeable about it.
>Much like Go gatekeeps generics to the language authors only
It would be more accurate simply to say that Go lacks generics. I don't know of many statically typed languages that have arrays but which don't allow you to type an array of integers differently from an array of strings. Go basically has that feature, plus built-in hashtables that are also type parametrizable. Characterizing that as some kind of huffy refusal to allow people other than the language authors to use generics is arguably inaccurate. Adding generics to Go would require fundamental changes to the type system, and would have some nasty interactions with interfaces. It's not a matter of flipping a switch.
Go's omission of user-defined generics was a conscious decision by Go authors led by the belief that the benefit is not worth the complexity added and that devs would misuse it; yet this did not hold them back from special casing generic support for things they implemented themselves. This is what I'm comparing it to.
What it would take to add generics to Go now is a separate matter. Feel free to link my Go commentary to my point on lack of type classes on Elm if you want to see it from the perspective of changing an existing language.
>yet this did not hold them back from special casing generic support for things they implemented themselves.
My point is that essentially all statically typed languages allow parameterization of built-in datatypes. C does this, for example, since it distinguishes arrays of ints from arrays of pointers to ints. No-one usually says that C has generics, special-cased or otherwise. The idea that adding generics is "just" a matter of extending parameterization of arrays to user-defined data types seems to be largely limited to anti-Go rhetoric. The implicit suggestion is that the Go designers could have chosen to allow users to parameterize their own types, but didn't do so because of [insert bad intentions]. In fact, adding a true generic type system to a language is a vastly more complex undertaking than merely allowing parameterization of built-in types. It totally makes sense that a language designer might decide to do the latter but not the former. It's not an arbitrary restriction tacked on because Rob Pike doesn't trust you to use generics correctly.
I don't think I've ever seen the Golang creators talk about devs misusing generics. It that's ever been said, it's in the context of compile time. The argument has always been about avoiding complexity at compile time, and within the compiler, which I think is a very noble goal.
One of the reasons behind the poster saying it is that the interop between Elm and vanilla JS is quite painful especially compared to the likes of BuckleScript.
PureScript's interop is fairly easy, too. Just foreign imports, which I personally prefer over mixing languages like you might do in BuckleScript/ReasonML with their brace syntax (or might not), but it's still better than this weird message passing thing that Elm does.
I would expect that interop wouldn't be trivial - the impedance mismatch between a mutable and immutable world would be difficult. I didn't know of BuckleScript though and that faces a similar problem, so it's interesting if it significantly better.
Elm is in no way an alternative to HTML+CSS. It is an alternative to JS as a way of doing work client side (it does in fact compile to JS).
The 'view' functions in Elm return HTML (represented using an ELM DSL for convenience) that is added to the DOM and so then rendered using some CSS provided elsewhere in the normal way.
I have a vastly different experience:
At CurrySoftware we used style-elements[1] to build a internal frontent for a client.
The whole project only contains 15 lines of HTML that sets up the elm-app. Zero CSS or other HTML.
Try it out. IMO it changes everything about frontend development.
Do you have any experience of how easy it is to add accessibility information or attributes when using style-elements? If it generates its own HTML and doesn't give you access to things like ARIA, that is a concern.
Thank you. I hadn't heard of this and it's really interesting. What are the downsides of that approach? Is style-elements as full featured as you'd want?
It is pretty much fully featured as what you would need in any typical web-app.
One crucial thing that is missing is guaranteed browser support. That is why we only used it for the clients internal frontend. But as I understand it, this will be addressed in the upcoming 5.0 release.
Also the resulting HTML is not always as optimal as I would hope.
All in all development is just so much faster and cleaner. No need to worry about layout and style. After using style-elements for a while, HTML + CSS seem like a really stupid idea to describe layout and style.
That's not much different from a React app, in terms of how much HTML needs to be involved. As low as 9 lines, if you want (basic HTML scaffold + root element).
I'd think a particularly adventurous person could do it without writing any HTML and just create the scaffolding directly in the DOM before the app is mounted, but that would be a little silly.
This is interesting, but how accessible / semantic is the markup it produces? Is it smart enough to see that I'm iterating over a list and producing an element for each item, and output <li>, for example?
Working on an elm project now and a few months in I believe I might see the main wart if elm which is the amount of boilerplate required. I suppose that should shock no one because elm might be many things but feature rich is not one of them. I still like it though. And boilerplate might be easier to read than some bad abstraction. Still it ends up less dry than I would have liked.
Unfortunately, I am unable to read the article on my phone. The code examples do not render properly. They extend off the left and right sides clipping most of the code. Some sort of word wrap or shrinkage might be better.
I couldn't be happier with Elm in this project. Many major refactors: instead of the usual white-knuckle experience with prior languages/frameworks, it was, like, zen.