Elm is Wrong
reasonablypolymorphic.com
reasonablypolymorphic.com
I spent the first few weeks of my first Elm project fighting against the language, trying to emulate type classes, build abstractions, do things like I would in other languages and generally having a bad time. Eventually, and with slightly bad grace, I conceded to the current limitations of the language and did things the Elm way, accepting that sometimes things are bit boilerplatey and cumbersome.
Now my second large Elm project is currently in its first round of QA, and the difference to similar projects in Angular or React is striking. There are no (and I mean ZERO) runtime errors that have popped up during testing. When QA find a bug, its instantly clear exactly where in the codebase the problem is, and usually simple to fix. So far most serious issues have ended up ultimately being consequences of a poor choice of design/modelling that, when fixed, has ended up in a higher quality overall codebase.
Yes, things could be better, and I'm sure they eventually will be. We would all like the kind of abstractions you talk about in your article, but in my real-life experience it turns out that you don't need them to write powerful and high quality code.
And hey, when these kinds of abstractions do arrive I'll just refactor my code, and know that the compiler will tell me when its done. Imagine doing that in Javascript.
That's unlikely, it is not the direction Evan wants to take, and so far the language has gone the opposite direction on purpose and by design.
> And hey, when these kinds of abstractions do arrive
Which they probably won't. Realise that the Elm platform is written in Haskell, Evan knows about these features, he could have used them and he very specifically avoided doing so. If you want these abstraction-building tools you'll be much better off looking at e.g. PureScript rather than wait for Elm to add them.
I am pretty sure I read somewhere on the project homepage that you should not do this but do things on the elm way.
I'm a Python programmer. I fully expect dict keys to be able to be arbitrary objects. But after coding a lot in JS, I realized I could live without it. It's nice, but it's not a show stopper if I don't have it.
Same goes here. Yes, typing is not as good as you wish it was, but Elm is a young language, give it time to evolve. In the meantime, what about the innovative things in it ?
I'm a Python programmer too, and I also fully expect dict keys to be able to be arbitary objects, and I get really frustrated with the fact that they can't be arbitary objects. They have to be hashable objects, and the hash function refuses to hash certain objects that it has decided aren't allowed.
If you have a list or dictionary you want to use a key, you can convert it into a tuple which would make it immutable.
If you don't care about performance for larger collections you could just use a list instead of a dictionary, which does not require hashing. Changes to the original mutable object will also be reflected in your list.
> What would you expect to happen if the object is modified after being inserted into the dictionary?
I would expect it to continue to use the object. Why would it matter if it was mutated or not?You can try it right in your browser with Javascript and the Map() object type. You can mutate the object all you want, as long as it's the same object(-reference) you access the same value in the Map object. Just as I would expect. "Mutable" doesn't change which object you have, only what it looks like inside.
It's also worth pointing out that user-defined objects operate the way you seem to desire (e.g. default to using the id() property of the object to derive the hash). So in my mind, this strikes the perfect balance?
StdLib types that are immutable bake in more comparative hash properties while making it trivial for a user to wrap them and override this richer behavior with default hash based on id().
Consider:
```
>>> class myList(object):
... def __init__(self):
... self.inner_list = list()
...
>>> x = myList()
>>> x
<myList object at 0x10bdabf10>
>>> x.inner_list
[]
>>> y = {x: 'hi'}
>>> y
{<myList object at 0x10bdabf10>: 'hi'}
>>> x.inner_list.append(1)
>>> x.inner_list
[1]
>>> y
{<myList object at 0x10bdabf10>: 'hi'}
>>> for k in y.keys():
... print k.inner_list
...
[1]
```
> This fundamentally reduces the usefulness of hash representations though.
If you want something immutable just put something immutable in? > Instead of thinking of dict keys, think sets.
It's the same that I already wrote for sets, and also the same I just wrote: If you want something immutable just put something immutable in.By the way, I'm not talking about any particular implementation.
> If you want something immutable just put something immutable in.
My point is what do you expect if you do this:
>>> x = (1, 2)
>>> y = (1, 2)
>>> set([x, y])
I would argue that you would expect:
>>> set([(1,2)])
Since x is equal to y. But if you base the hash by default on id, you would get:
>>> set([(1, 2), (1, 2)]) # set([x, y])
Since x and y are different instances (have different id()) properties. I would argue that it's more useful/predictable for built-ins to hash based on content rather than id().
However, you can still hash based on id() but simply creating your own object (as I demonstrated). So you get sensible defaults for built-ins but also the option of hashing mutable objects.
Anyway, it's configurable for example in Java (http://stackoverflow.com/questions/9440380/using-an-instance...) - default is to use the reference but you can override object methods to change that. Similarly for C#(http://stackoverflow.com/questions/634826/using-an-object-as... or http://stackoverflow.com/questions/8952003/how-does-hashset-...).
For me, talking about how dicts handle hashing keys and sets hashing members are equivalent in the context of the Python language.
Given that context I was saying changing the "hashable" nature of default objects would be counter-intuitive as the new behavior would be in contrast to the expected behavior of sets and/or immutable equal types in dict keys.
This question is sometimes not important: When the mutable object is not mutated.
Which you can't guarantee when the object is mutable, so for consistency's sake it's left out.
Though you can always build your own Dict subclass and implement __hash__ on it and be angry with yourself when it fails. :)
https://docs.python.org/3/glossary.html#term-hashable
http://stackoverflow.com/questions/4348232/python-dictionary...
For set, it's a bit more annoying. But for dicts. twice in 10 years maybe ?
I mean, its not a huge deal, but it adds up.
You can use pretty much anything as a dictionary key
For example (tested on both python 2.7 and 3.4):
>>> {{'a': 1}: 2}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'dict'
>>> {[1,2,3]: 4}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'list'
>>> {{1,2,3}: 4}
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
TypeError: unhashable type: 'set'
Objects inheriting from object are hashable by default, but the hash is based on the objects instance such that each instance will return a unique value for that instance: >>> class A(object):
... def __init__(self):
... self.x = 1
...
>>> a = A()
>>> b = A()
>>> d = {a: 1, b: 2}
>>> a.x = 10
>>> b.x = 10
>>> d[a]
1
>>> d[b]
2
While this makes sense for the instance stored in the dict (because mutability would otherwise mean that they key changes values), I don't think this is particularly useful. I rarely look up dicts by instance, but rather by value. That is, I would construct another object with the same attributes and look up by that.You can, of course, implement your own __hash__ to make it work, but you have to do it manually for any object you want it and most third-party objects won't have implemented it so you'd have to monkey patch them.
Contrast that with Clojure, where all built-in data structures (maps, sets, lists, dicts etc) work as keys out of the box.
[1] I guess its true in the sense that you can implement __hash__ to make it work. But its not particularly easy or idiomatic.
A language designer may limit the power of abstraction intentionally; maybe the abstraction taxes performance too much; or maybe too much power scares the target users. That's a plausible choice, but that also turns some users away.
I can accept this in old languages. I can accept this in embedded languages. I cannot accept this in a language that is supposed to be about programmer productivity.
Basically this patient has one bullet hole in their heart. One. This doesn't make the patient dead as the author seems to let you think.
On the other hand C++ is only just about to get its first version of Concepts. (Haskell programmers in this thread: imagine if you waited 10+ years to get typeclasses.)
My point being that most languages are going to be missing something you wish they had.
```js var m = new Map(); var o = {}; // some object m.set(o, 5); m.get(o); // 5 ```
So, if you need objects as keys in dictionaries, then there is a big chance that you can use transpiling already (modules, other ES6 features).
Please, don't take it as an offence, just a suggestion – I really don't see a problem here.
That guy who thought markdown was supported by hacker news. LOL ! I've been through that too...
That said, I agree 100% that the ability to form abstractions is a critical part of any language that hopes to become a tool that larger teams and projects can adopt. Without type classes and convenient mutability, I don't see Elm achieving widespread adoption. (That said, it could gain those features in the future.)
I've been working on a language inspired to some degree by Elm but also by my experience teaching Haskell. Haskell has amazing expressive capabilities and type safety, but the unfamiliar syntax is a hurdle that many people don't care to jump. To that end, we've designed Crux to have much of the expressive power of languages in the ML/Haskell family, while being as familiar and lightweight as JavaScript or Python. The idea is that it's something you can pick up easily but it can grow with you and your project.
Some articles on the design thinking: https://chadaustin.me/tag/crux/
The website: http://cruxlang.org [It's a preview!]
But as a practical platform to build real apps? No way. I mean you can build apps with any tech, so of course people will try and succeed with it; but it's just a bad choice.
Elm is impratical because you can't do anything with it. I loathe directing attitudes in that field where everything moves fast (http://www.martinfowler.com/bliki/EnablingAttitude.html).
Its creator is a bit on the control freak side and far more of a backend dev than a frontend dev. The reactive framework (the Elm architecture) is full of boilerplate and anything that was not forethought will have to be a metric ton of more boilerplate or delegated to javascript via asynchronous ports (if you have to hide the crap away in JS land because it's impossible to do in elm, somehow it's not elm's problem). The elm community is minuscule and not always great, doesn't embrace new approaches (the ones who do don't stay for long as it's so frustrating) they're more like robots repeating "wait for Evan to tell us how to do that. If Evan didn't say anything yet, you are taking big risks" or "Evan is working on this particular problem, just wait 2 years"
Meanwhile we can build apps real fast with typescript, which in version 2.0.3 is a very capable and more than typesafe enough language.
bucklescript/Reason might be a good alternative to the very closed Elm ecosystem too if like me you like ML.
I think where elm shines is as a simplistic language and sanitized environment to teach people programming. That's about it. It's still in a state of a "research language" (and it's good at it), but is not being marketed as such.
Also, why all the hate? As you said, neither you or the TypeScript community have any reason to feel threatened by Elm, which nevertheless has had a very positive influence on the mainstream JavaScript community (look at Redux).
The only impact your comment could have is discouraging the Elm community from furthering its valuable research in the field of web development. Please write constructively next time.
For someone who hasn't worked with a statically typed language yet, perhaps. But someone who knows and works with Haskell would disagree here.
The line from Evan, Elm's creator, has always been along the lines of "show me a concrete actual use-case that you can't do without typeclasses", this article fails to clear that fairly low bar.
The other elm article from the other day about select boxes did a much better job of identifying that not having a way to enumerate Enum types is a bit annoying.
Translation: "I will never add typeclasses."
There is no concrete actual use-case that is impossible to implement without typeclasses. What typeclasses make possible is an abstraction over concrete actual use-cases. That is, you can always solve individual concrete actual problems with boilerplate. Typeclasses "only" give you the possibility to write that boilerplate once and for all and reuse it for every concrete actual use-case.
Evan seems to think that that's not worth it, which is a valid opinion to hold. But it would be a bit more honest to come out and say it like this.
First you need to figure out what exactly the Elm community wants and needs. Once you have a pretty good idea of that, you can start prototyping things. Elm is still young, and the most pressing concerns for using Elm in production is not the lack of interfaces/protocols/typeclasses, but stuff like debuggers, which is what Evan is working on.
I'm sure we'll see some tool for ad-hoc polymorphism in the future, but not in the short term.
As for typeclasses, I think Elm's stance is perfectly reasonable. Typeclasses aren't a pure win, they have downsides too:
- They couple the term level to the type level by allowing values to depend on types. This makes it impossible to compile or interpret a program without first checking/inferring its types. Static types without typeclasses don't have this problem; as far as I can tell this even includes dependent types (which do their coupling the other way), as long as you don't allow some form of typecase.
- Global uniqueness of instances doesn't compose. If I have a perfectly correct module A, and a perfectly correct module B, a module C might break by importing both, due to overlapping instances. This has to be mitigated by convention, e.g. not writing orphan instances.
- Local reasoning can require knowledge of global properties. This is especially true for things like code generation. For example, if I plumb together two expressions, say `nub :: Eq a => [a] -> [a]` and `xs :: [b]`, I can generate new requirements like `Eq b`. However, I can't just go ahead and implement those requirements (e.g. generating an `Eq` instance for `b`), since that will break if there's already an implementation, floating somewhere in the sea of imported modules. Packages like `ifcxt` can help, by allowing lookups and fallbacks, but they're not a complete solution.
- If more than one instance of a typeclass might makes sense for some type, it's pretty much inevitable that APIs using the typeclass (e.g. `foo :: Bar a => a -> ...`) will gain extra functions for bypassing the typeclass (e.g. `fooBy :: (a -> ...) -> a -> ...`)
There are probably more issues in the literature, but these are ones I've been banging my head against recently.
Typeclasses are a great idea and a useful addition to the PLT toolbox, but including them in a language isn't an automatic improvement: it's more of a design choice to steer the language down a particular path, when other languages may prefer other paths. Similar to using strict/non-strict evaluation, or exceptions, or macros.
Every function that a language support/does not support shapes the ecosystem, and that is arguably as important as the language itself. With Elm, decision making is done by a small group of people and they can be quite opinionated.
I started when 0.15 is out, amazed by how beautiful FRP can be, then it is gone now. I cannot add / remove fields from dictionary, I cannot have multi-way if. My code base is still simple, so I can get around it, but I really enjoyed the good old FRP style. In JS, you can definitely choose your favourite frameworks, but in Elm, there is no alternative, there is only a single HTML framework `elm-lang/html`, if they decide to drop FRP, you cannot escape! This also means choosing Elm is also choosing to follow Evan, you are betting on a person.
I hope things getting better someday, we will have a standard JS interop that allows people to make their own 3rd party frameworks in Elm. Competition makes things better.
I am not an elm user, but I follow from time to time, and they seem substantially equivalent looking at the migration guide[0]
[0] https://github.com/elm-lang/elm-platform/blob/master/upgrade...
I don't like the tone of this article, otherwise critique seems to warrant more discussion. Elm as a language is in development and community is very vibrant and open... as long as you don't mention rules for formatting, one in particular ;). So, I really wouldn't discount Elm so quickly.
On the other hand, PureScript and Reason also look very interesting and I am looking forward to get more familiar with them. I think we live in fantastic times.
Having the language maintainer need to bless packages with native bindings is strange, though. Tag the packages so that people know they use native bindings, then people can decide whether or not to trust them. You cannot build an ecosystem through one person.
The article makes some great points; however, the title is not particularly useful nor a good summary of the article itself.
I have enourmous respect for Anders Hejlsberg and his work but Typescript is not an answer. Typescript is limited in sense that from the beginning it was doomed to be just a superset of Javascript. And we all know about deficiencies and "bad parts" of Javascript.
Languages do matter and those with strong functional emphasis are better, because they enforce you to pursue specific discipline that allows you to write better code.
Of all functional languages (more or less popular today) in my opinion the best option is Clojure and Clojurescript. Clojurescript is simply amazing. It's robust, easy to learn, fast, adaptable, pragmatic, can cover your needs on all major platforms including iOS and Android. For a long time advocates of statically typed languages would point to one "weakness" of Clojure - its dynamically typed nature. But to begin with dynamism of Clojure types always considered its strength. Besides, Clojure today carries an instrument far more powerful than static types - http://clojure.org/about/spec. Clojure community is growing, language is gaining popularity. Because behind seemingly innocuous, and even arguably (at the first sight) not very appealing lispy syntax, there is an incredible elegance, power and true astonishment.
So he then decides he wants to have the full Elm experience by trying to replicate a Haskell solution in Elm using a technique that was mentioned in an issue comment. I feel like in trying to avoid the blub paradox, he ran right into it.
Need is not the word I'd use. IIRC (from some Github issue I saw recently) Evan has said they are adopting a "wait and see approach" on typeclasses and/or other type system extensions. Given how young Elm is, I see this as a careful and considered approach to its continued development, rather than a statement that its creators consider it to be finished and complete as it is at this time.
I've jumped ship on things for far less than a "need", just because there was something better. I expect that a lot of people use Elm despite any perceived deficiencies because they think it's still better than the alternatives for their application(s).
I'm not saying "Elm is bad", or whatever.
> A language can be better than its competitors/alternatives while still having room to improve.
I agree with you is all I'm saying. I never tried to imply otherwise. All I said is that there is no reason to think that Elm has to have typeclasses right now to be useful, as some others seem to suggest.
We don't "copy-paste the same stuff over and over." That would suck. Why would we be excited about a language that made us do that? Our Elm code is about as DRY as our JS code was before, except the Elm code is way easier to maintain.
You need only look in the standard library for examples of boilerplate and not-DRY code. The map function is implemented separately for Lists, Arrays, etc.
I really want to love Elm. But the more I wrote it the more I realised that the only answer to those questions is that you solve them with boilerplate and brute force. When I ask the community what the solution is I'm largely ignored or told it's not a "real" problem.
If there's shared logic between update functions we extract it into a helper function. That also makes it easier to test.
I'm not sure how typeclasses would make composing update functions easier, but in this case we can be concrete. PureScript's Pux library implements the Elm Architecture, and PureScript has typeclasses. Would you mind showing me some Pux code that uses typeclasses to improve the situation you're talking about?
I don't write PureScript, I can't help you there.
I follow the same pattern in a 10k Javascript/React app I'm working on professionally. I don't see another way of doing things. Not that I'm looking very hard, cause this really isn't a problem.
In that case, is it really boilerplate?
The fact that NoRedInk are perfectly happy without typeclasses (or something similar) could be an indication that it really isn't as important that people would make you believe. After all, there are several languages out there with support for typeclasses (or something similar). Like purescript. And yet, people decide to use Elm.
I think that Evan and Richard are personally invested in the language and can't see it's shortcomings.
One of those is irrelevant and the other one is false.
There's a lengthy, clear description of a problem, with a use case, leading up to a feature request...how is all of that "unconstructive"?
In fact, what's definitively unconstructive is the way the feature request is closed: dismissing the use case as invalid, despite the fact there's a description of the rationale behind it in the comments.
People who ignore the point to come here and complain about the tone, also further detract from the point.
FWIW, I find it extra hilarious that, in the context of employment search, I would form an opinion based on how - or what - a person _vents_.
this sounds like a great way to never learn to play guitar
Consequently I had many of the same complaints, though not quite to the extent or wording he does, so I made my own TEA-like library on Bucklescript/OCaml and ported many of the Elm examples to it, most were basic copy/pastes with the most minor of syntactical differences (`with` instead of `|` and so forth, basically Elm->OCaml differences), I have it up (with code link) at http://overminddl1.com/bucklescript/ if anyone is curious. Not production worthy by any stretch but I do clean it up and add more and more to it over time, already can do near all that Elm's libraries can do, in addition to some of the community libraries.
Continuing on the article, he basically re-implemented OCaml's Witness style (done via OCaml's modules), it was fascinating watching someone build it in Elm I must admit.
He does focus too much on typeclasses, the witnesses he wrote is the way OCaml does it (although with a bit less syntax, and much more an upcoming update), which is not a typeclass form, but something similar.
An aside, where he mentions 'If you don’t want to read the essay, SYTC essentially says “hey, why don’t we pass around an object that describes the implementation of the contract that we care about, rather than having the compiler infer it for us?”. If you’re familiar with Scala, this is how they implement typeclasses in terms of implicit parameters. If you’re not, SYTC is equivalent to passing around a vtable whenever you want to invoke code on a dynamic target.', that is just what OCaml is doing in a soon-coming version with its implicit modules. Definitely looking forward to that, even if they are just fluff. They are basically like Scala's implicit parameters but with type lookup based on module definitions, still explicit, but significantly reduces the code required to be written.
>I have complaints about Elm after using it during a quick hack session.But his(/her?) major complaint is valid: lack of type classes, which completely kills essential composability and generic properties of Haskell. And the module system doesn't offer MLs features to make up for it (signatures).
This means that Elm requires boilerplate for things that are elegantly handled by type classes.
You may also look at Purescript [1], a more complete Haskell inspired language compiling to Javascript.
Haskell is a complex language. So I'm not necessarily saying that Purescript is a good choice for the average developer unfamiliar with functional languages.
Elms 'lack of features' makes it easy to pick up. Especially if you aren't familiar with FP. But Elm is TOO simple.
> Knowing what TEDIOUS JOB GHC is doing for us helps us appreciate more the convenience of type classes.
Thanks for the link though, I think I read it a few years ago.
Without typeclasses, that simply doesn't happen. I'd say 90% or more of Haskell typeclass usage is pointless, and maybe half of what remains is simple to replace with simpler polymorphism or no polymorphism.
For instance, almost everything here:
https://wiki.haskell.org/Typeclassopedia
is replaced, in Elm, by just having an explicit module reference, so Maybe.andThen instead of andThen. No joke, that replaces essentially all of it, except some stuff that's not used that often.
To replace the non-trivial cases is going to require pattern matching, it seems. If your types change, then you are going to have to update things in multiple places.
But, like you said, it's not the end of the world. In many cases the intent will probably be clearer. Still, I'd rather have type classes than not.
For a Haskell programmer, what he tried to do (use typeclasses) is extremely common. It's some of the most basic stuff you can do. Elm is clearly modeled after Haskell, and absolutely fails to maintain the basic patterns that Haskell users take for granted.
Put another way: if you try something and find it flawed—why should you put any more time and effort into it? And yet, that doesn't mean the problems you found were not real. If anything, those problems might be the most relevant because they forced you to put the tool down.
At one point, he said this witness "proved" something ... so is this coming from "propositions as types"?
You might like this article if you're interested to learn more: http://jozefg.bitbucket.org/posts/2015-01-09-constructivism....
In my own words, a "type witness" is a Haskell idiom (maybe broader?) that allows you to perform dynamic casts.
Here's the first example from that link:
A simple witness type might be defined over the Int, Bool and Char types like so:
data Witness a where IntWitness :: Witness Int BoolWitness :: Witness Bool CharWitness :: Witness Char
dynamicCast IntWitness IntWitness pa = Just pa
dynamicCast BoolWitness BoolWitness pa = Just pa
dynamicCast CharWitness CharWitness pa = Just pa
dynamicCast _ _ _ = Nothing
No.
A lot of people in the Haskell community have yearned for this as well, and the latest version of the Haskell compiler will support something similar called Backpack.
data Dict k v = D (k -> k -> Bool) [(k, v)]
empty :: (k -> k -> Bool) -> Dict k v
empty f = D f []
-- and so on
Of course, this is a naive linear-time implementation; substitute with whatever alternative you like. If you already have some type-level "comparable" thingy, you can make an "emptyFromComparable" to pre-populate with the built-in compare function.We could do the same for things like Set too.
As far as I can see, the only 'problem' would be operations like `merge`, where we might have two different functions. The simplest thing would be to bias in favour of one, e.g. turning `merge d1 d2` into something like `extendWith d1 d2`.
I'm not saying this can replace typeclasses or modules in general, but in these sorts of cases we're already passing around a datastructure, so why bother passing around the required functions separately?
There's probably some irony here, considering the fact that GHC implements typeclasses using dictionary passing!
[0]: http://ocaml.org/
[1]: http://ocsigen.org/js_of_ocaml/
1| https://www.scala-js.org/ 2| http://typelevel.org/cats/ 3| http://scalaz.github.io/scalaz/
If you program in JavaScript and you want a language with no runtime exceptions, go for Elm. If you want type classes, go for PureScript.
Maybe look into https://github.com/clojure/clojurescript ?
What the author described here is a linear order, not a well ordering, despite linking to the correct Wikipedia page.
Ok, I'm jesting. And I like static typing. But sometimes it is easy to get lost in it when you just want to be productive instead.
It is a remarkable for one person to create a language, runtime, repl, debugger, compiler to another quirky language i.e. JS that is usable to the point that people are doing professional work in Elm. Also the compiler produces easy to understand messages.
Evan has made Functional reactive programming more accessible. I don't think I would have a chance to understand FRP at all without Elm. Elm has inspired other frameworks in Purescript and the development of ReactJS.
Sure Elm is not perfect. I found that much of the JS ecosystem not viable in the Elm world, even with FFI due to the purity of the virtual dom. I can't just go and easily chuck an impure calendar control in my code.
However despite it's drawbacks I feel the article was a bit strong in putting down Elm, which is sad because I think there are the seeds of some great future languages and ideas in there.
Especially when the facility in question solves a real PITA of a problem.
Now, the author was obviously venting, he even admits it. Nonetheless, the complaint is justified.
Also, It's worth noting that Elm does have a BDFL. Evan makes the call and, as I'm sure a lot of python folks would agree, that setup means that the language is going to remain consistent, clean and well defined. This might be frustrating, but is part of keeping a strong design philosophy that directs the language. In that context, is it really a valid criticism?
Evan actually addresses this issue directly by talking about the different communities with different aims. He says that having these different communities with different design decisions makes the whole scene a lot stronger[1]:
> if you go back a year so on the mailing list you'll see a lot of people talking about type classes "when are we going to have this in Elm?", "we need this", "this is the most important thing", and a language came out that had different priorities and all the people who wanted that kind of feature started using that language and so now that's not to say one of the communities is making a better choice than the other, it just means we can all experiment with a different philosophy and way of thinking and do well."
The existence of a BDFL is irrelevant. This rejection is frustrating whether it comes from one person, or a committee, a peer, whatever, because it is arbitrary and unjustified. The feature wouldn't compromise the design philosophy nor its consistency. "I don't want this" is not a design philosophy, and neither is "your use case is invalid".
The use case is actually solid. Writing readable, maintainable code which is conceptually easy to understand in the span of a few paragraphs, like in the blog post.
[1] https://github.com/elm-lang/elm-compiler/issues/1283
PS. I'm certain evancz has a reasoning behind his wish to keep the feature out of Elm. He just doesn't communicate it, which makes the decision seem arbitrary.
I think fundamentally he's correct, but the point that he is missing is the intended audience of Elm. He was not it. Elm is much easier to grasp than Purescript, for instance. There is less complicated syntax and there are less complicated features. I would would be quite happy to use it in a team that isn't familiar with FP and who wanted to use it for front end code. In fact, although I have yet to do a large project with it, I might even lean toward Elm over JS/CS and React. It just seems a lot more straight forward, with less options available for hanging yourself.
But, like I said, generally I agree with him wrt a general programming language. Purescript is a much better fit for that. I thought about trying to write some Elm code on server side, but it just seems like putting a square peg in a round hole. Also, having played with it, the code generation in Purescript seems really, really good. I have no trouble envisioning what it's going to generate for me, which I like.
I investigated Elm just after the 0.17 release, decided I was fine with it but didn't really love the language. I've since moved to investigating F# and the Fable compiler. While it's unlikely that someone who prefers Purescript would prefer an ML derivative, I feel I should mention it for other people reading the thread from the front page and prefer having imperative escape hatches.
The Ocaml to JS compilers (Bucklescript/js_of_ocaml) also produce nice js output but my background with Clojure has left me enjoying the benefits of being a functional language that's part of a larger ecosystem and I'm comfortable enough with .net core to be willing to treat F# as a viable language outside windows.
I have looked at Elm, and Purescript and now Bucklescript, but I have not yet seen, or wired up myself, something like the Elm architecture.
I should probably buckle down and learn the wiring I need myself, but I have been finding the typing a little tough.
[0] https://github.com/paf31/purescript-thermite
> [writing] some Elm code on server side [...] just seems like putting a square peg in a round hole
We are actually writing server-side elm for a living. We mostly have a Scala background and we actually think elm is a pretty great fit for backend code.
Agreed, the absence of typeclasses is a limitation of the language. Yes, it means, you can't have a `Set RandomObject` or `Dict RandomObject SomethingElse` (among other things) and that can get pretty frustrating for folks coming from almost any other strongly typed language.
However the real question here is not "is this language worthless because of that", but rather "can I overcome that limitation for my specific use case ?".
My personal take : - If you are considering a switch from JS to elm (server or client), the point seems moot, as the language features described here are far from being available in JS. - elm suits _some_ server side application very well. Not _all_ server side application.
[0]: https://www.seas.harvard.edu/sites/default/files/files/archi...
Elm has inspired ... the development of ReactJS
I don't think that's true. React is a descendant of XHP, and predates Elm. Perhaps you were thinking of Redux?I could just as well suggest you mentally substitute the phrase helping the needy with kicking puppies whenever you encounter it.
Could you provide an example of when it doesn't?
The term political correctness (…) in modern usage, is used to describe language, policies, or measures that are intended primarily not to offend or disadvantage any particular group of people in society.
However, a lot of writing (academic, journalistic, what have you) has "getting at the truth" as only one of its goals among many, including "expressing my feelings," "attacking someone else," "playing with poetic language," "sounding smart," etc.
Being nice is good.
He came to Elm expecting a Haskell for the web. Elm has the completely opposite philosophy of keeping things simple, even if it means extra boilerplate.
I can understand OP's frustration, but if he watched a few of Evan's talks (like this one https://www.youtube.com/watch?v=DSjbTC-hvqQ), he would realise his expectations about Elm are wrong. Also, he forgot that Elm (just like any other open source project) doesn't owe him anything. That's why many people take an issue with his tone.
In summary, Elm's target audience are JavaScript developers. It's developers who want their apps to be more robust and easier to refactor than in plain JavaScript. Sure, type classes are useful but they also increase complexity. Evan wants to see if there's a better solution and the Elm community generally accepts that.
We can't take issue with his tone by appropriating information about Elm's direction in an ex post facto manner. The guy - whatever guy - is a newcomer to Elm, picks it up, see an obvious deficiency, asks (quite politely, I might add) about a feature addition, gets a dismissive answer. That's the context. We can't apply Evan's* rationale behind the reply here, because the OP never had the chance to have it revealed to him to the extent of his interaction.
I'm surprised I have to point this stuff out. However understanding we may be, surely we can see why anybody is frustrated with being dismissed like this?
* Apologies, but I don't actually know Elm's author's last name.
The deficiency was only in his eyes though. Evan and the Elm community are fully aware of the type classes thing, because it's been mentioned by many people. He just doesn't see it as something that requires an immediate solution.
To summarize: I understand OP's frustration. At the same time, Elm (just like any other open source project) doesn't owe him anything. If you open a pull request or an issue you are not guaranteed a resolution in your favor. Ranting will help you vent but that's it.
Yeah!
Just create and maintain your own damn dialect of a language!
It's OPEN SOURCE, that means you automatically know and are an expert in anything it involves!
It's 2016, we can stop with that meme now.
No, I don't think that's true. He came to Elm hoping there would be some useful ways to create abstractions in the language (that doesn't necessarily mean there has to be typeclasses. in fact, the whole article his him pursuing an alternate method of abstraction), and besides creating a function there really is none in Elm.
You must resign yourself to write the same boilerplate over and over. It is impossible to keep any large Elm project DRY.
Analysis in depth is a useful thing for not only the creator who is likely to already understand the trade offs he has made but for other current and potential users of the language.
Then we'll either have to change all those commentators, or the original author – since one of the arguments against faul language is that it distracts.
Agree. [0]
[0] Substitute FRP for Subscriptions ~ http://elm-lang.org/blog/farewell-to-frp
Actually, you can... as long as you properly isolate the control. Here is a prof of concept that does just that:
I feel like RxJS and Cycle.js both make functional reactive programming quite accessible to JavaScript developers without the burdensome overhead of an entirely new language for the frontend.
Have you used these frameworks, and if so could you articulate why Elm would be a better alternative?
Can you give a few examples? Google is not being helpful.
Whenever you read "X is offensive", mentally replace it with "I find X offensive". The substitution emphasizes how little being offended ought to matter.
Your finding this piece offensive does not create an obligation on the part of anyone else. I am growing very tired of social critics attempting to turn the world into inoffensive mush. We need more articles of this kind.
> It is a remarkable for one person to create a language, runtime, repl, debugger, compiler to another quirky language
I agree that the effort is remarkable. The idea that the strength of the author's effort should somehow shield his work from criticism is antithetical to excellence. It's participation trophy culture. If we're to create great work, we have to understand the difference between good and bad work, and we can't do that if misplaced concern for someone's feelings stops our describing reality as it is.
"I decided to write a detailed story about events surrounding the French invasion of Russia, and the impact of the Napoleonic era on Tsarist society, as seen through the eyes of five Russian aristocratic families; since I haven't used the language before, for kicks I decided to do it in Swahili. This blog post will summarize why I hate Swahili and why it's totally unsuitable for writing about Tsarist Russian society - or, I would say, anything else. Swahili is awful and needs to die."
Seriously, how can people write blog posts like this? You decided to code up a new project in a totally new language, and are here to tell us why that new language is awful. Really? Really? It's not like this is uncommon. People make these blog posts all the time! What's with this?
-------------------
EDIT: I got downvoted, but look:
>A few weeks ago, on a whim my friend and I decided to hackathon our way through an app to help us learn how to play guitar. In a stroke of inspiration, we decided to learn something new, and do the project in the Elm programming language, about which I had heard many good things.
>Consider this post to be what I wished I knew about Elm before deciding to write code in it. Since I can’t send this information into the past and save myself a few weeks of frustration, it’s too late for me, but perhaps you, gentle reader, can avoid this egregious tarpit of a language where abstraction goes to die."
It doesn't take "a few weeks" to learn a programming language!!!
No, it doesn't. It takes a few hours.
Which, I'm sure sounds flippant, but hear me out. In the 25-30 years I've been a professional programmer, I've been paid to use many different languages. FORTH, Fortran, C, C++, Pascal, Protel, C#, Java, Perl, Ruby, Go, Javascript/Coffeescript, and Python are the ones that come off the top of my head, but if I were to go through my CV, I'd definitely remember a few more.
Anyone who has programmed in a handful of the above will notice that (with the exception of FORTH) these languages are practically identical. They all have slightly different features and slightly different syntax, but once you know one, you can pick up another one pretty easily. Especially once you know 5 or 6 of them, you practically don't even need to look at the docs. Just glance at some example code and you are on your way.
Libraries and frameworks take a lot more time than languages. There are lots of crazy details that you have to remember. Luckily, most of the major languages of the same type have very similar base libraries. As long as you stay away from frameworks, you can be productive pretty much immediately. Learning the details can take a few weeks, but mostly its unimportant. Frameworks suck. I've been working in Rails on and off for... 4 years???? I'll never put that damn thing on my CV. I still don't understand how it works.
So, I don't know this author, but he is clearly knowledgeable in Haskell. Maybe he also knows Ocaml. It would take you about 15 seconds to pick up Elm from that background. The rest is discovering (and apparently complaining) about the bits that don't live up to your expectations. He didn't comment on the state of the libraries (except to complain about the political process for getting libraries distributed with the official tools).
I'm not going to defend his rant. I didn't enjoy the tone and I think he completely misses the point of why the language is there. But his technical complaints are perfectly reasonable.
I didn't vote you down, but I suspect the reason other people did is that you are a bit too quick to criticise the author's ability to accurately judge the language. He seems perfectly capable, even if I disagree with his conclusions and his tone.
I think you really go into superlatives here. It's not fair for you to say "15 seconds", for example. 15 seconds is how long you've been reading this comment.
(I just timed myself, okay maybe 10-13 seconds.)
I also think that "a few hours" is an exaggeration on your part. Let's pick a language you've never used - take Objective-C which is similar to C# and C, C++ which you've already listed, and I think you've never programmed in it, because if you had you would probably have listed it.
Okay, so now make a serious iOS app in Objective-C in "a few hours". As in, have one by this time tomorrow. See? It's crazy. That's not how it works.
Maybe the weeks and months and decades run together for you, but there is a huge difference between doing something for a few months or a year, or doing something for a couple of weeks as our author reports. I don't like his kind of blog posts, and it is a whole category - there is this whole type of blog post where you pick something you've never used, use it to do something new, and then complain about it, all within the space of your first week or two using it.
It strikes me as kind of ridiculous. Especially with a provocative title like "Elm is wrong." Literally, it's like Tolstoy writing War and Peace in Swahili, a language he didn't know, and then writing a blog post "Swahili is wrong" -- all within the space of two weeks of when he first learned Swahili. I might be exaggerating slightly, but I think my analogy holds. It's almost farcical.
Elm is particularly easy to pick up for people coming from Haskell. Maybe not in 15 seconds, but 15 minutes is a totally reasonable estimate.
The author can without doubt write a large project in Elm. His complaints were about missing the conveniences of abstraction Haskell-like languages provide, and he is more than qualified to talk about it.
Decomposing records into tuples of comparables has probably crossed his mind :)
Well, all right. In general I would say that is not true even for languages that are close, but there are exceptions and I suppose I can take your word for it.
It would be interesting to compare with the opinion/experience of someone who didn't know Haskell, well, right? (Though in that case perhaps the learning curve is too steep, maybe Elm isn't meant for that.)
If you're coming from Haskell, you'll see Elm as a dumbed down, stripped version of Haskell, which will trigger in you the feelings it triggered in the OP.
But then making an iOS app requires picking up frameworks/libraries, not only learning Objective C, which was exactly GP's point:
>> Libraries and frameworks take a lot more time than languages.
"Unfortunately, Elm isn’t a library. It’s a language, which just happens to have a great library"
I don't know why we're arguing about this. It's another blog poster writing about something new they tried for one particular project, and in this case literally "why it's wrong". (After two weeks.) It's hard to take seriously.
Clearly 15 seconds is unreasonable, and in retrospect I regret having written that. As I am trying to convey what a reasonable amount of time is to understand a language, using unreasonable numbers is unhelpful.
From my experience, if you were to give me a legacy Objective-C application and ask me to fix a bug in it, it would take me much less than an hour to understand what I need to know to fix that bug. It would literally take me seconds to understand the syntax well enough to read the code, only being slowed down occasionally to look up syntax that I didn't understand. (To be fair, I have already fixed many bugs in Objective-C programs before, so I know exactly how long it took me -- despite not "knowing" the language at all).
If you asked me to write an Objective-C program from scratch, it would take me 10-20 minutes to get started. My main problem would be in choosing appropriate libraries. For example, I like to TDD, so finding a good test library would take me some time (though I can live with XUnit and the chances that there isn't one for Objective-C approaches zero).
If you ask me to make an iOS application, it would take me at least 1 day, probably 2, to get set up and start writing code. This, of course, has nothing to do with Objective-C and everything to do with figuring out how to get the build system working, etc.
It would take me at least a week to get to a point where I'm writing idiomatic Objective-C for iOS apps. It depends on how much code I could find on the internet. Free software is great for this, but there is precious little for iOS (in comparison to other platforms). On the other hand, if you asked me to write a GNUStep app, it would be much easier.
It would take me years before I was actually knowledgeable about iOS. No, scratch that. It would never happen. I have absolutely no interest in becoming an expert in iOS.
But let's back up here. How much knowledge would I need to have to critique Objective-C as a language. Again, I urge you to read the original blog post closely. The author opines that Elm is fundamentally broken as a strongly typed FP language because it doesn't have type classes. This is what he says is "wrong" about Elm.
He is correct. There are no two ways about it.
Now we can argue all we like about how Elm programmers can work around this deficiency. I think he's missing the point that Elm is aimed at programmers who do not want to deal with the complexity of a fully featured strongly type FP language. We can debate about how front end programmers (the likely target for Elm) will rarely run into situations where they absolutely need type classes... But he's correct in his statement.
He's expressed his opinion in an offensive way and he's turned a blind eye to the fact that people can still enjoy many of the benefits of the language, even with this obvious problem. But he has not made an error in his analysis.
And he didn't need weeks to discover this. It's very clearly stated in the tutorial. He could have saved himself weeks and read the damn thing. It would have taken him 20 minutes. And then he could write the same offensive piece and still not be wrong.
The reason I'm pointing this out is that it is beneficial as a programmer to realise what is easy and what is hard. Many young programmers (that is to say, programmers who have written only a few thousand or a few tens of thousand lines of code), conflate frameworks with languages. It's easy to miss the distinction between the features of a language and the features of a framework.
Why is it important? Because if you understand the features of a language it will serve you well going forward. There are only a few categories of languages in the world. Everything is just a different spin on that category of language. If you learn a few examples for each category, you will never have trouble finding work in your career. It will take you hours to jump from one environment to the next. I'm nearly 50. That's why I'm still employed.
But on the other hand, frameworks and libraries have endless variations. And you absolutely must understand certain details or else you will be in for a world of hurt in the future. The downside, though, is that the framework/library will give you no benefit at all when it is dead and buried. How many DB2 programmers did I go to school with that are useless today? How many MVC programmers did I work with that are useless today? .NET, iOS, Android, PHP, Rails, insert-flavour-of-the-moth-here. Before you are finished your career, they will all be gone (or good-as in terms of furnishing you a living wage).
The author seems well qualified to make the statements he makes. He does so obnoxiously, but obnoxious != wrong. He's spent much more than the amount of time he needed to come to his conclusions.
I get the fact that you hated his blog post (and that you hate obnoxious know-it-all blog posts in general). I hope I have convinced you to take another look and understand the distinction between what he's trying to say and what you thought he was saying. There is a lot of valuable stuff in there. Even if it is obnoxious.
So let me skip the part where I spend 2 weeks picking up a language!
Let's go straight to: "if an ostensibly open language only has one single implementation, it is fundamentally broken and underspecified and should not be used by anyone, period."
Is the part I quoted enough for me to conclucde that it's a broken language not fit for any use by anyone? Because the article that we're talking about has the title "Elm is wrong."
Can I say, "Perl 6 is wrong" without even bothering with coding in it for a few months?
Given the response in this thread, I can only surmise it was a well chosen title for a blog post.
A better example would be back in the old days perl had no intrinsic OO support. Instead it had a library that made a few things easier. But basically, the OO support was hashes that pointed to functions. There was no syntactic sugar at all.
As an OO language Perl was fundamentally broken. You could still write OO code in Perl (and I happily did so for a very long time). But, yes, there were many people who claimed that Perl should be avoided because of this. Eventually full OO support was added and those voices died down.
The difference between that situation and this situation is that the author of Elm (as I understand it) has absolutely no intention of adding type classes to Elm. He has specifically chosen not to have them because he thinks it complicates the language. I happen to think that for his target audience, he is absolutely right. I think it is a good decision.
However, for the author of the blog post, the decision is wrong. Elm is intentionally broken. The author does not want to fix it and the blog post author thinks that this decision is wrong.
He also complains about the maximum size of tuples. The author of Elm believes that you should only have small tuples because you should be using records instead. This is contrary to how FP languages tend to work. Usually you use tuples. Records are the strange structure to work with. Again, I agree with the author of Elm, but the author of the blog post has a completely valid point. In his opinion, Elm is wrong.
The author of the blog post found a way to get around several of the problems he was having with Elm, but it required him to add or remove fields in records. The author of Elm had disabled that feature because it was complicated. Given that doing this removes the only way the blog post author (and me too) has to work around the lack of type classes, he was upset. Even though I understand the blog post author's frustration, I agree with Elm's author. JS implementations are optimised for objects that don't change structure. Records are implemented with JS objects and so allowing the records to change structure will impact performance in ways that the Elm programmer won't expect. It's a pity, but shit happens. Of course the blog post author thinks this is wrong.
Finally, it's not like you are locked down here. You can easily write an extension in JS to fix the issues the blog post writer has. But the kicker is that JS extensions can not be distributed with the normal Elm tools without approval from Elm's author. And Elm's author has said that he doesn't want those things fixed. So even if you wrote a work around, you aren't allowed to distribute it.
So given all this, I hope you can see the blog post author's point. Elm is fundamentally broken. The Elm's author knows that is broken and refuses to fix it. The only way inside the language to work around the broken feature was removed and Elm's author doesn't care. You could fix the problem by writing an extension, but Elm's author has blocked that avenue as well. You are not allowed to fix this problem.
This is what he feels is wrong. I completely understand his point of view, even if I disagree with his conclusion. Your characterisation of the situation trivialises it. You assume that there is no way the blog post author can know what he is talking about because he hasn't used the language long enough. You haven't spent the time yourself to understand what the issue is and why the blog post author is upset. You just assume he is a dumb ass. That's why you were getting voted down.
I spent a lot of time trying to explain the situation to you, so I hope at some point you find it valuable (even if it doesn't seem so right now). Like I said, sometimes I get the impression that spending my time on things like this is worth it. In my past, some people have graciously spent similar efforts to help me understand something and eventually it was helpful to me. I hope that will be the case here.
The post's tone is a bit harsh and could be more respectful. After all, there is no consensus for type classes, [ML's modules being an alternative](https://existentialtype.wordpress.com/2011/04/16/modules-mat...)
Nonetheless, the post is interesting and worth the reading because it raises true questions. For instance, I was surprised to learn that adding a field to an extensible record was no more a feature.