Elm 0.19.1
elm-lang.org
elm-lang.org
+ The language syntax is very nice and refreshing.
+ It's a joy to work with the compiler.
+ If it's compiling, it's working! No runtime exceptions.
+ Static typing!
+ Functional programming!
- The language doesn't have component composition (like in React or Vue) and you end up having huge chunks of spaghetti code (but to be fair, it kind of works because of the compiler).
- It's complicated to implement routing and to build a Single Page Application.
- Only pure functions in Elm, so doing API calls and generating random numbers are unnecessary hard.
- It's a pain to parse JSON.
- There is no variable shadowing, so naming your stuff is harder than it should be.
- Vue embraces HTML, Elm avoids HTML, and it's really a pain to build HTML view in Elm. <div><a href="hello">world</a></div> becomes div [] [ a [ href "hello" ] [ text 'world" ] ]
- There is a lack of leadership and community building in this project. We don't know what's going on and where the project is going. It's like a black box. No roadmap. All issues on Github, all posts on Elm Discourse get no response.
So in the end, Elm is an interesting beast, but I think it's too academical and not really practical for serious projects.
Pure functions are definitely a selling point. Random number generation needs to be in an isolated part of your app unless it's a toy. Because it deals with IO much like reading from disk, it should have a "hard"-ness to it.
Good luck!
showUsers : [User] -> Html msg
showUsers users = div [id "my-component"] [ul [] (map showUser users)]
showUser : User -> Html msg
showUser user = li [] [
span [class "firstName"] [text user.firstName],
br [] [],
span [class "lastName"] [text user.lastName],
]FWIW, I wrote this without having previous Elm experience—the compiler's error messages are so good that it was mostly trial and error until it worked.
To your point: I think using language primitives for defining views instead of HTML templating is an advantage for Elm because you can write them using only the Elm language itself, without having to learn yet another syntax. Combined with the excellent compiler error messages, it makes writing views easier and less error prone than writing HTML templates.
What's even the "good luck!" part for? Good luck knowing about List.map?
How far do you think he got in Elm?
(def users
[{:firstname "john", :lastname "snow"} {:firstname "Peter",
:lastname "drucker"}])
(defn my-view
[]
[:ul
(for [{:keys [firstname lastname]} users]
[:li firstname " " lastname])])Of course it does. Exactly like React.
> It's complicated to implement routing and to build a Single Page Application.
not really. It's part of the core libraries in 0.19. Probably simpler than the "react-router" alternative I suppose.
> It's a pain to parse JSON
Probably for a beginner. But once you learn it once, it's trivial to handle most JSON cases.
> Elm avoids HTML
The opposite, the libraries are almost 1-to-1 mapping to HTML elements, so it's as close as it gets.
> I think it's too academical and not really practical for serious projects.
Most definitely not the case.
If you want to respond, try to have a more empathetic approach to addressing a newer users concerns than “of course it does ... not really ... the opposite ... most definitely not the case”.
If new users cannot understand how to do things correctly in the language, that’s a problem. Note that new users does not mean they are new programmers, simply new to your language or way of doing things.
> has given the Elm community a bad reputation
The Elm community is actually very welcoming. Not sure where you read about that reputation. I was also struggling a lot when I started, and the slack channel is extremely helpful. So you can go there, ask those questions and see if the above are true or not.
Not sure how to address them in a more constructive way.
You can state your exact same opinion without it coming across as dismissive just by stopping that one thing.
This applies to probably all technologies under the sun, so not very helpful.
The problem is it lacks these advanced features for users that already know advanced FP, AND it has features that are too advanced for people that are beginners in pure FP. Elm suffers from trying to please everyone but pleasing no one in the end.
This is completely the opposite in my experience. There is a massively strong hierarchy of leadership, core development and active users. All willing to help at all times. There are quirks, sure - but it is by far the most accepting language community I've been a part of. The Discourse has been a fountain of information: have never had an unanswered query before, and don't see many of them around at all.
Um... yea it does. Elm makes functional composition very easy which which means it's very easy to compose "components" (which are just functions anyway).
> - Only pure functions in Elm, so doing API calls and generating random numbers are unnecessary hard.
I would say that Elm makes doing API calls and generating random #s appropriately hard. Elm strives to corral side effects into one part of the Elm architecture: "commands". By doing this, you're keeping all code that contains side effects at the fringes of the walled garden you're growing.
I think this explicitness/discipline is needed in more codebases.
> - It's complicated to implement routing and to build a Single Page Application.
I agree, it's no Ember, which comes with all the bells and whistles of a full router system, including page transitions, transition errors, data fetching, etc. Richard Feldman has an elm SPA example on github that shows how to create routes, pages, etc. The official Elm Guide also has sections on routing, etc.
> So in the end, Elm is an interesting beast, but I think it's too academical and not really practical for serious projects.
Too "academical"? Tell it to these devs: https://blogg.bekk.no/using-elm-at-vy-e028b11179eb.
It's actually not that easy to write composable components in Elm, and attempting to do this has always been officially discouraged.
For the example described in the below article, I think channelPanel and chatPanel can be looked as components.
https://korban.net/posts/elm/2018-11-17-elm-ui-introduction/
My analogy there is Agile. Years ago no company would do agile and probably because no other company was doing it. Then Thoughtworks etc. started doing it, and slowly the proof that it can work spread around. I think this could happen with Elm.
But like agile I think there is some counter-intuitive ideas, sort of 'go slow to go fast' type of things that you need to get your head around.
I struggled and still struggle but I want to give Elm a fair go. My peeves were:
1. Can't component-ize like React.
2. Lots of 'boilerplate' to wire things up.
3. No promise like API for async, you need to do stuff via pub/sub and ports.
However the counter points seem to be that.
1. You don't need components - design a good model data structure and work out from there. There is a good video talk about this at an Elm conf.
2. By making us us wait and use ports for a lot of things in the meantime (and not just adding everything to the language or letting anyone use vanilla JS in their packages) the modules that you do use are "pure" and are almost guaranteed not to crash. And the API's of Elm are well thought out because there is no rush to fill in all of the web platform.
This sort of thinking sounds like the "100 year language" way of thinking that PG writes about. What sort of language will we be using in 100 years? Hopefully something well thought out, not full of baggage because it was rushed.
Yes you can, whether should, is a different question. You can have a ton of mini TEA components.
> 2. Lots of 'boilerplate' to wire things up.
Very true. Generating code helps with that.
> 3. No promise like API for async, you need to do stuff via pub/sub and ports.
What are you using async for? API requests? Then those are async.
But can you make parent-child communication with these mini TEA components like in React or Vue? It seems to me that we can't.
2. I think the boilerplate is good in making things explicit.
I think Boilerplate is the lack of a more succinct way of expressing your intent. So, boilerplate is never good in making things explicit, it's just the (current) shortest way possible to accurately expose your intent.
For example, in TypeScript, if I delve into making datastructures `algebra-ish`, I always have the boilerplate of defining a `tag` field in my objects, and lengthy switch-constructs to match on the tag field. It's not good in making things explicit, it's actually just the only way (at the moment).
But in react is is natural to say "oh I need a spinner, let's make a functional react component for that". And you can always keep some local state in React and avoid the message passing relay-race you'd have in Elm with the same approach. So Elm benefits from a different approach.
I think parent-child communication isn't necessarily the right way to tackle problems.
Otherwise, I'll link to the oft-linked "Child-Parent Communication in Elm: OutMsg vs Translator vs NoMap Patterns" [1].
[1] https://medium.com/@_rchaves_/child-parent-communication-in-...
IMO, this is one of Elm's biggest strengths. The Elm HTML syntax is a million times easier to reason about and build hierarchies in, than HTML. The syntax is cleaner and easier to read.
(For the uninitiated - each HTML tag in Elm is a function that takes two arguments - a list of attributes, and a list of functions that return HTML.)
Yes but it gives you a nice guarantee that you will get a (handled) error at parse time, every time. In JS etc. you may never notice until you maybe render that one prop 4 levels deep under a certain UI combination and its a demo for your client.
Frankly, with something like serde in Rust, it's such a pain to deviate from the 1:1 case that you tend to stick to the 1:1 datastructure despite how suboptimal it is, maybe manually transforming it after parse time if you can be bothered. I don't find that to be any superior to Elm's simple combinators.
My experience with Elm's codecs is that there's a small learning curve if the concept is new to you. And then after some real world experience you wonder how it was ever alien at all. I wish I had it in every other language I've worked with.
http://hackage.haskell.org/package/aeson-1.4.5.0/docs/Data-A...
That's a very surprising oversight from a language that claims to be functional.
And issues: at least they are known and logged, and people discuss work-arounds, that's something.
Only pure functions: yeah, that's the point of a functional language, isn't it?
Variable shadowing: many languages don't have this, IMO it's a feature. You can always simply prefix local variables with "l_" or "a_".
Pain to build HTML in Elm? Don't get this. It looks slightly different, that's all. As soon as you start adding your templating code, it gets messy when you use HTML.
It told me the lib import was prob a typo, with suggestions, and WebGL at the top:
You are trying to import a `Webgl` module:
11| import Webgl
^^^^^
I checked the "dependencies" and "source-directories" listed in your elm.json,
but I cannot find it! Maybe it is a typo for one of these names?
WebGL
Set
Svg
Array
Hint: If it is not a typo, check the "dependencies" and "source-directories" of
your elm.json to make sure all the packages you need are listed there!Both those technologies have well-earned reputations for having not-so-shallow learning curves, but that's almost not an issue when the tools always make it clear what has gone wrong.
One similarity to this post that sticks out:
> Maybe you just try the JavaScript way to see if it works:
Given that the final syntax for async/await was a bit controversial (postfix .await), the compile folks implemented parsing for (at least) the JavaScript way of doing it, and so you get a good error message telling you the correct way:
error: incorrect use of `await`
--> src/lib.rs:2:5
|
2 | await bar()
| ^^^^^^^^^^^ help: `await` is a postfix operation: `bar().await`
This kind of thing can really help polyglots, as well as people new to the language.A human/e interface to compiler errors is critical to me. It means the difference between the compiler being an ally and the compiler being an enemy (or maybe a teacher who thinks you're just a bad student and is going to give you a bad grade no matter what, not that there's any scar tissue there).
Matters the world to me personally in terms of my enjoyment and flow and represents the kind of computing I want to do.
I have not personally had the usecase for Rust just yet, but it is the only language I have never heard a negative thing about. That's huge, with how opinionated developers are.
The arguments for the language and general consensus are so strongly positive that without having used it myself I frequently recommend it (I passively follow the language's progress online).
A huge part of it is the developer ergonomics, a large amount of which comes from your compiler error messages.
When I talk to people about the gold standards, Rust and Elm are the examples I give.
Thank you guys for all your work!
Still in spite of that, I think it's an awesome project with a lot of enthusiasm behind it, and I'm happy to see languages exploring new ideas getting so much attention.
I suppose you can't have everything, but in my experience top level inference makes code a lot easier to read because it removes a lot of noise and redundant information while largely leaving the "intent" of the code in place.
fn foo() {
String::new()
}
fn bar() {
foo()
}
fn main() {
let s: String = bar();
}
Imagine you modify foo, and now you're accidentally returning a Vec, not a String: fn foo() {
Vec::new()
}
fn bar() {
foo()
}
fn main() {
let s: String = bar();
}
You'd get an error like this: error[E0308]: mismatched types --> src/main.rs:10:21
|
10 | let s: String = bar();
| ^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected type `std::string::String`
found type `std::vec::Vec<i32>`
You changed foo, but the error points to bar, in main. None of this is related to the code you changed. But in Rust today, you'd get error[E0308]: mismatched types
--> src/main.rs:2:9
|
1 | fn foo() -> String {
| ------ expected `std::string::String` because of return type
2 | Vec::new()
| ^^^^^^^^^^ expected struct `std::string::String`, found struct `std::vec::Vec`
|
= note: expected type `std::string::String`
found type `std::vec::Vec<_>`
This points right to the issue: you're returning a vec, and not a string, in foo.There are other issues too; global inference and subtyping have problems. While Rust doesn't have subtyping generally, we do in lifetimes...
Beyond all of that though:
> it removes a lot of noise and redundant information while largely leaving the "intent" of the code in place.
Rust's perspective on this is that the type signature is what communicates your intent. It's like a unit test. You write down what you expect, and then the compiler's job is to check that your code does what you said you were going to do. This seems like philosophically at odds with what you expect, which is fine of course, but is probably where a lot of the divergence comes from.
I read this all the time about Elm, but did you actually try Elm for a real world project?
I did, and Elm error messages were one of the most painful point of the compiler: they're beautiful but very often completely unrelated to what's actually going wrong. They actually drove me away from the actual errors more than once.
I'm actually writing Elm at work and we have two separate Elm apps in production.
YMMV but Elm with elm-graphql has been the most productive and confident I've ever been writing frontend code.
There are a few example errors here: https://github.com/rust-lang/rust/issues/36611
Are the annotated code snippets after the first line useless with screen readers? I wonder if there’s a flag to hide just the snippets.
I can still remember how I didn’t understand a thing ( was just starting my internship) but still knew that he would achieve great things with Elm.
So happy to see him succeed and being able build such an amazing community just by being himself.
Finally, I love how his personality has become a part of the language, most obvious when reading error messages.
fyi compilation speed has had a noticeable improvement as well with this release, but is not mentioned in this blog post.
The one problem, for us, is when there is an Elm project the developers _not_ working on it are jealous of the developers who are.
It is fun to work with.
I think it because the compiler is freeing your brain from trivial issues and allowing the brain to focus more on creative problem solving.
1. How community contribution is handled. I’ve been following the compiler repo for a year now, and the number of bug reports (and PRs) that remain open is concerning. I get it - they want to move slow and be deliberate in the way it is developed. But fixing well known compiler bugs shouldn’t take a year. Makes it harder to sell to dev teams.
2. Using private packages. I know there have been workarounds (including multiple src directories tracked via git), but they feel hackish.
I’ll continue using Elm for personal projects, but it is still a hard sell.
We've recently hit 100k loc for our main frontend written all in Elm. The journey from inception 2.5 yrs ago has been amazing and now we're in full production mode, reaping the rewards of purity and the type system.
The compiler is so friendly. It feels like Evan Czaplicki is talking to me directly. :)
[1] https://elm-lang.org/news/small-assets-without-the-headache
I really like the Browser module recently.., it enables people to build more things easier, that solves serious problems people trying to use Elm seriously.
I am not sure how Elm evaluates feedback from language users. Elm is too much focus on new comers, make it so new people are excited about it first week, and then get stuck on things they want to actually build, and move on.
https://package.elm-lang.org/packages/elm/core/latest/List#m...
The docs example even shows it being used as a zip.
I can say now that the Elm community is VERY responsive to current devs, and Elm's development is not just focused on new people, but that is where the blog posts and updates focus because, frankly, it's a new concept that Elm is focusing on that many languages do not currently, so it bears mentioning and makes for better updates than normal esoteric patch notes would (which any power user CAN still find).
But Elm's development is really out of focus in the sense of fulfilling, fixing what people using it seriously encounter. I don't want to mention specific things where its solution is "use port".
I just have to figure out what's the best way to wrap JS libraries, but I am sure there is a way.
Your elm.json says this application needs a different version of Elm.
It requires 0.19.0, but you are using 0.19.1 right now.
Smile to my face! So I came here. Awesome :-).
Elm worked great, and we had no problem having several developers contribute to the same project without stepping on each other, with everyone able to read each other's code.
It's been 100% stable, predictable, and reliable. And, yes, we're calling JavaScript via ports. Works well.
Link: https://blogg.bekk.no/using-elm-at-vy-e028b11179eb
HN discussion: https://news.ycombinator.com/item?id=21204761
(Evan, the creator of Elm, also works at NoRedInk)
https://github.com/Lattyware/massivedecks/tree/v2
That's the current development version (the master is still on Elm 0.18). You can see it in action at https://massivedecks2.herokuapp.com.
And on top of that, it's a blog post. Evan gave examples of really helpful error messages.
I don't use elm, as I don't do webdev and I don't agree with Evan's tendancy to minimalism, but I really wish other languages had the "pair programming" aspect of the elm compiler.
Being able to do frontend development that /just works/ when it compiles is fantastic. I have yet to use Elm for anything serious because I mostly do backend work, but if I need to Elm would be my choice. No more 'undefined is not a function' mysteries or trying to figure out what part of the latest Javascript framework is stopping me.
Elm has the basics of what you need to develop frontend applications today, even though I'm sure there is work to be done yet.
In special if you try a NEW lang. Lets say I wanna check elm, I try it a little then BANG! weird errors. I will quit, not matter how cool the lang is.
When learning something new, even if you are experienced (I have used professionally more than 12+ langs now) you "budget" to learn something is low: New syntax? New paradigm? hard to install? Limited tooling? Nothing work? Not stackoverflow explains of that error?
You quit in any step of this chain. I glad ELM designer is smart to fix one of them
BTW: Rust is similar here. It have decent error messages.
Also perhaps a mode where I could instruct the compiler to fix the error itself (like the closing brackets) and continue the compilation as far as it can and then output the "fixed" code. That might be a dangerous feature, but it could also be a fun feature to auto-gen your code without knowing much of the language :-).
Or maybe you read the documentation section "Importing modules" which takes you 5 f*ggin minutes? That's a lot less to ask than "implement very verbose error messages that talk to you like you're a baby".
My opinion at least.
So, if that's what you want, you already have every other programming language to pick from. Let the rest of us have our fun. I've been programming for 20 years and appreciate Elm's errors every time.
Why should I need to do any more work than read a compiler error when I accidentally write "import Webgl" instead of "import WebGL"?
>why so many projects can't even be fucked to flesh out a README
Not relevant.
>manpages are more hassle than just googling "how to unzip with tar"
Not relevant.
>Why should I need to do any more work than read a compiler error when I accidentally write "import Webgl" instead of "import WebGL"?
Still not relevant, since that wasn't the example given (correcting typos like this is indeed a very helpful compiler error; gcc does it for like a year or two now).
>RTFM bravado mindset
I really don't think telling people to learn a language instead of typing random things in hope that the compiler corrects them is being a hacker-neckbeard who tells you to rtfm. The example given in TFA is literally: "if you don't know how to import things yet, instead of reading the introduction, googling "elm import", or literally just taking 2 minutes to figure it out, just type what you would do in some other language, and the compiler will gently tell you how to import a module in Elm", or in other words "type random stuff until it works". Should the compiler also correct the user if they write `#import <set.h>`? Or `open Set`? Or `from Set import `? Again, in my opinion* this is neither relevant nor desirable.
What does that mean? Should he have NOT responded to your comment? Does that then mean that you should have not responded to his comment? Does that mean I should have not responded to your comment? Does that also mean that you shouldn't have made a comment, since Evan directly expressed his thoughts and opinions in his post? Should we stop communicating at all and become Loopless One-Directional Communication Graphs? Who shall be the original Opinion Holder? Adam or Eve?
Anyway.
> Should the compiler also correct the user if they write `#import <set.h>`? Or `open Set`? Or `from Set import `? Again, in my opinion* this is neither relevant nor desirable.
If it can, why not? Why not tell the user: Hey, you've got `xyz`, but you can only do `zyx` with those literals. Having detailed Errors is not a detriment. I remember my first Segmentation Fault in C. Man, I cried.
Programming languages have users, and caring about the User Experience of a language (i.e. Developer Experience, I supposed) is commonly desirable. There is no downside to a good error message, neither for something as trivial as imports, nor for common things like using the wrong key names in a Record.
I make heavy use of types in TypeScript, but the error messages when something is out of order (ever so slightly) is just so brutal at times, with error messages being 20+ lines long, where only the last line might be relevant. I, for one, welcome our helpful error message overlords.
It was more in response to the downvotes, with are (supposedly) not a disagree button.
If you've got examples of cases where we can do better, feel free to file an issue! We want to do better.
Thanks for letting me know.
Now I just need to wait until Typescript 3.7 trickles down to all my dependencies so I can get that goodness. Sigh.
Sigh.