
Making Elm faster and friendlier in 0.16 - jwmerrill
http://elm-lang.org/blog/compilers-as-assistants
======
boubiyeah
I find the Elm language quite fun and I think it has potential.

However, I'm absolutely not convinced about "the Elm architecture" for
anything but the simplest UIs. Is pure functional reactive programming
suitable for ambitious UIs ? I do not think so.

React has its own set of flaws but at least I believe it nailed the state
problem: Encourage the minimization of local state but still make it easy to
have some when necessary. I like functional programming a lot but I think this
is a case where good old object oriented encapsulation provides a more
pragmatic solution.

There are all sorts of transient states that a parent's component shouldn't
have to care about (Whether I currently have focus, a transient list of
changes not yet committed that should be thrown away should I navigate away,
is the calendar drop-down opened?, etc, etc) Elm makes it hard to have truly
rich and reusable components for that reason as all that transient state must
leak to the parent components.

But that's still doable at least, if cumbersome; some other things simply
appear impossible, like coding a ReactTransitionGroup equivalent. This React
component encapsulates the concept of a changing-over-time list of children
and animate in/out the children that changed across two redraws. It needs to
know about the previous list of children to diff it with the new. It needs to
manipulate the actual Virtual nodes passed to it so that it temporarily leaves
the exiting nodes till their animation finished, etc. This thing has tons of
state and it needs it to do its job; and it's fine. How would you do this in
Elm without leaking the abstraction at every call site ? (I'm looking for a
pragmatic, easy-to reuse by everybody solution, not some convoluted sliding
Signal of component lists ;-) )

I'm wondering whether performance tweaks should be the focus right now; Elm
already had good performances. The issue is adoption, and if it's too
convoluted to write (non trivial) reusable components, I don't see how it can
succeed. Right now I would never start a complex project with it in fear of
getting stuck with a medium-complexity task because the architecture didn't
foresee my problem.

Maybe the architecture provide some escape hatches I didn't see, and I would
love to be proven wrong.

~~~
rtfeldman
Local component state is the new two-way data binding.

Three years ago, two-way data binding was the gold standard for niceness. Then
React came out, and there was buzz around unidirectional data flow, and a lot
of (understandable!) skepticism came with it.

If you listen to people who have spent a lot of time with two-way data binding
and unidirectional data flow, what you hear are a lot of unidirectional data
flow converts and not a lot of people saying "yeah it wasn't awesome so I went
back to two-way data binding."

We're watching the same thing play out with local component state versus a
single state atom architectures like The Elm Architecture, Redux, etc. As with
the React transition, there is understandable skepticism around new things
claiming to be nice, but the writing is on the wall.

If you listen to people who have spent a lot of time with both systems, what
you hear are a lot of single state atom converts and not a lot of people
saying "yeah it wasn't awesome so I went back to local component state."

~~~
nwienert
Actually, you do see a lot of questions and problems with the single state
atom. In fact, I'd argue it's inherently a side step towards a future that has
the best of both worlds: encapsulated state within components, but backed by
some global state store invisibly.

This is exactly what Relay is by the way. You component asks for state, and
gets it from a server. The fact that it comes through props is actually just a
downgrade because it means you must now treat it as some special thing, and
not variables.

In the ideal world, we can write simple components that fetch state from
wherever (remote, local, global). They store that state into themselves, and
it "just works". They can write back that state just like how they write
variables. And all of this "local" state would really be backed into a global
state store invisibly.

Local state - Pros: easy to reason about, easy to use. Cons: trapped in one
place, inflexible.

Global state - Pros: can be backed in various ways, easier to share. Cons:
Hard to use, harder to reason about.

Local state backed to global store - Has all the pros and none of the cons.
Unfortunately doesn't exist yet today.

~~~
christianalfoni
Hi there,

I do not quite agree with this. Though I acknowledge your sentiments :-)

1\. Global state is easier to reason about. If you have a single state store
expressed as a single object you only have to read one file to understand the
complete state of your application. If you let local state express the state
and the global state is invisible you have to look into all these local state
files and compose the complete state in your head

2\. When you define it as local state you risk conflicting with some state set
in a different component

3\. You still have to change state. If you define your state in your
components you will also have to include all the state changing logic inside
the component. Your components will become very hard to reason about. And what
if two components uses the same state and both of them needs to update the
state? You will need to put the same logic into two different components

4\. You could say Relay fixes this, but Relay just handles one thing and that
is state related to the server. We build applications that does a lot more
than talking to the server. Changing the state of your application is a huge
problem space and though Relay is cool technology I can not imagine anyone
expressing and changing all their state using Relay. So you need some other
concept(s) to change all the other state and multiple concepts for doing the
same thing is harder to reason about

Personally I think local state is a bad idea and currently I also think Relay
is too limited. When I jump into an application I need to reason about what
state it handles. With a global state store I can do that. Then I need to know
how that state can be changed. Ideally that should be one concept, but we
usually have lots of concepts for changing state. Then I want to see how the
UI is expressed. Components are great for that, except when they are filled up
with state definitions and state changing logic.

So from my perspective I am also trying to contribute with a solution :-)
www.christianalfoni.com/cerebral

~~~
nwienert
Good points. A response:

1\. Global state is easier to see on a high level, but harder to reason about.
Local state is inherently easier to reason about: it's right there. Global
state requires me now looking at actions/signals, global state structure, and
then my component, and resolving the three.

2\. They should definitely be synchronized, this problem is only specific to
local state implementations today. If they aren't synchronized, thats simply
at the lack of the system you're using. I'm not familiar with Om Next, but I'd
guess it handles this for you (as could any system properly organized).

3\. Not true. You could have state changing functions imported and used by
multiple components. This is also easier to understand, in my opinion. I can
see where the state is located, and still keep my shared state changing
functions somewhere.

I do think local state is skewed negatively now because it's very poorly done.
React, angular, all systems today make local state a total pain, opaque, and
hard to work with. Om Next seems to be a step forward (I'm working on
something somewhat related for JS that should make it better as well).

~~~
christianalfoni
This is really interesting, we have very different perspectives on how to
consume how an application works. Not saying you are wrong at all, just have
different perspective :)

1\. When I say "global state" I mean the actual state, actions and signals are
state changers, not state. A global state store looks like this:

{ admin: { users: [], showConfig: false }, home: { isLoadingNotifications:
false, notifications: [] } }

This is one file. If you use local state this example would be split into
maybe 3 different files. I think we both agree it has to do with how many
files you need to look into. And the amount of composition you need to do in
your head.

2\. It would be interesting to see Om Next in JavaScript syntax, too much
brainpower going into trying to read Clojure :) Not because it is bad, just
have not learned it

3\. That is true, but now it is conceptually no different than signals/actions
and for that very reason. You should look into a different file to read the
state change. I think it is a good thing. State changes are often very
complex, surprisingly complex. They should not be inside a component. I think
a component should only be about rendering UI. State changes should be
expressed by a different layer.

So what I think is interesting here is that we seem to look at the app from
two completely opposite sides. I do not care about the components to
understand my app, because they just express its output, the UI. My app is
really the state defined and the way it changes that state. What I do care
about though is having dumb components is that makes me able to do universal
apps, just move my app to a new UI output like react-native etc.

It will be really interesting to see how Om Next affects the JavaScript
community. We are good at getting ideas from other languages and practices,
where Elm is a good example :)

Again, not stating that you are wrong about anything. It is nice to go into a
component and understand how that component works. Its just in my experience
really bad to use a "view" as a container for state and business logic. That
said it is really important to be open minded and I hope to see us grab ideas
from Om Next. Actually trying to inspire creator of Baobab to bring in some
new ideas :-)

------
mdm_
I'm just finishing up a first-year course at McMaster University where we
learned basic CS concepts (divide and conquer, state machines, recursion,
algebraic data types, FRP, etc) using ELM. It's the first time I've ever put
an honest effort into learning a pure functional language, and although it was
initially frustrating to a self-taught programmer with a background in several
procedural languages and SQL, it's growing on me, and I'm probably going to
look for a side project (maybe a small game or a simple CPU simulator) to
build with ELM when the course is over.

I only wish the "Improved error messages" and "Catching more bugs" features
had been introduced about three months ago, probably would have saved me
hours!

------
nathankleyn
Some of these errors remind me of Rust and the attempts in that community to
give every error an exhaustive description [1].

This looks fantastic, and shows a true commitment to reducing friction with
the language - a goal which often goes too long without attention.

[1]: [https://github.com/rust-lang/rust/issues/24407](https://github.com/rust-
lang/rust/issues/24407)

~~~
steveklabnik
Yup, I would strongly agree. Diagnostics are one of those things that's easy
to let slip by the wayside, but we've seen a huge payoff for users with all
the time we've invested in ours. Glad to see other languages like Elm help
raise the bar here too.

------
hellofunk
Elm is a beautiful expression of a language. Alone, it is a work of art. Put
to use, it lets you build works of art. One of the best contributions to
modern languages.

------
Apanatshka
Long anticipated, and now finally here :) I <3 the type diffs, exhaustiveness
checks and TCO. Not completely sure about the removed syntax, but it's not
like I used it a lot, so I guess simpler is better.

------
notacoward
Very nice. I love the "beginner hints" idea, and explicit enumeration of which
cases are missing in incomplete pattern matches. Overall, the "compilers as
assistants" idea seems great.

------
laszlok
Finally TCO! Actually in my UI-heavy Elm programs it isn't that often that I
have to write functions with large recursion depth. But it is really
comforting to know that the compiler is analyzing my code and making it more
efficient. :)

------
bribri
Has anyone tried Reflex? Really interesting concept in Haskell + GHCJS
[https://github.com/ryantrinkle/try-
reflex](https://github.com/ryantrinkle/try-reflex)

I liked Elm but I felt the language was a bit limited coming from Haskell, ex
no type classes so you have List.map, Signal.map, Set.map, etc

Overall Elm is great in terms of tooling, setup, error messages, performance,
js interop though

~~~
ablesearcher
Reflex is great (and its author is a genius) but it's not really useful yet
for non-desktop apps. Because Reflex + GHCJS is impossibly slow on mobile.

As an experiment, try using chrome (iOS) or android to load this:

obsidian.systems/reflex-nyhug/

or this:

[https://obsidian.systems/](https://obsidian.systems/)

They're both reflex apps.

GHCJS is bees-knees. But unfortunately, minimizing-code-size/mobile-
performance has not been a priority. (It's understandable, as Luite can't do
everything himself.) (Aside: the best solution I've seen -- in terms of
generated code size -- in GHCJS-land right now is:
[https://hackage.haskell.org/package/react-
flux](https://hackage.haskell.org/package/react-flux). Anecdotal, though.
YMMV.)

I can't wait for GHCJS to be ready for prime time. I wish all these alt-JS-
haskellish language authors (of Purescript, Elm, Roy, etc.) would just work on
making GHCJS better.

It's a bummer that Clojure and Scala are much newer than Haskell and yet they
both have a mature, production-ready JS compiler. The statically typed ML-
family is too small for multiple JS compilers. The entire community needs to
pick one and let the others die. Otherwise, we end up with several half-baked
solutions and not a single industrial-strength one.

~~~
purescript
> I wish all these alt-JS-haskellish language authors (of PureScript, Elm,
> Roy, etc.) would just work on making GHCJS better.

All three of those have very different goals and trade-offs from GHCJS.

I agree that it would be nice to share more work/knowledge though. One of the
nice things about AltJS is that several languages can coexist in the same
codebase.

~~~
ablesearcher
> "All three of those have very different goals and trade-offs from GHCJS."

And therein lies the problem. In my view, the most important goal is to have
at least _one_ really good AltJS-Haskellish language with a fully-featured
ecosystem of libraries. (I'm fine if that language is PureScript, btw.
PureScript is fantastic.) The problem -- which Clojure and Scala programmers
seem to have sorted -- is that our community is too small to support several
Haskellish-AltJS compilers. Do we really want several perpetually nascent
solutions?

> "One of the nice things about AltJS is that several languages can coexist in
> the same codebase."

Theoretically, you're right. But how many production code bases are there in
AltJS-Haskell (vs. say, Clojurescript)?

~~~
galfarragem
Normally very smart people have an huge ego and hate politics. It's always a
pity to see so much potential wasted.

------
khgvljhkb
I wish the clojure compiler also had the explicit goal of making things easier
like this...

~~~
lemming
There is hopefully some movement in that direction after my talk at the conj:
[https://www.youtube.com/watch?v=kt4haSH2xcs](https://www.youtube.com/watch?v=kt4haSH2xcs).
I'm continuously inspired by Evan's approach and his dedication to the user
experience, and I hope to be able to bring some of that to Clojure.

------
sotojuan
Elm is such a pleasure to learn. I really need to sit down and write something
non-trivial with it one of these days.

------
methehack
I'm trying to decide between Elm and React/Reflux for the js part of a side
project. I'm concerned about learning curve and awkwardness of adoption if the
project ever turns into something someone else is coding on. I know they are
very different technologies, but I think others must be choosing between them.
Any thoughts from those who have tried both?

~~~
danneu
I personally like React + Immutable.js (for the store) + Redux
([https://github.com/rackt/redux](https://github.com/rackt/redux)) which is
more similar to Om and apparently Elm. It's actually the first Fluxlike
implementation I willingly use.

~~~
mercurial
I'm using the same stack (minus immutable.js, but I'm thinking on it),
combined with redux-simple-router. Apart from the usual problems associated
with Javascript, it works pretty well, and I feel it's easy to understand what
is going on.

On the other hand, there are some pitfalls. Since you may need to trigger
actions based on some transient state (eg, fetching data from the server), you
occasionally need to set flags in your store ("my state is dirty"). Forgetting
to clean up a flag will lead to tears.

------
excitom
My first thought on seeing this post was "Oh wow, people are still using the
elm email client". I guess I'm getting old.

~~~
Apanatshka
hehe, I see this every time on an HN post about a new Elm release. At some
point I'll have to look into that old email client, I'm curious what people
are talking about.

------
e12e
Apparently the web site is having some issues?

Google cache:

[http://webcache.googleusercontent.com/search?q=cache:http://...](http://webcache.googleusercontent.com/search?q=cache:http://elm-
lang.org/blog/compilers-as-assistants)

------
garyclarke27
If Elm had a dedicated library for io with Postgres functions (stored
procedures) would then become very attractive to my company, for a very
ambitious project we are developing. we store all state and logic inside db
safely firewalled by stored procs, so i'm looking for UI focused language/
toolset that is productive, functional and produces atractive ultra reliable,
performant html js. I don't feel good about the Sencha tools, my team
currently uses, so I'm looking around for alternatives. ur/web looks very
interesting aswell but the limited adoption with only 1 albeit genius
developer, is a bit offputing

~~~
ac2u
I don't understand, elm is for your browser based application, which can't
communicate with postgres anyway except through a web server sitting in the
middle.

~~~
aflinik
That's true, although I see no reason Elm couldn't be compiled to server-side
JS running in Node.

I'd love to see some full stack solution that would abstract away separation
between backend and frontend (like Meteor perhaps) using some sane programming
language and architecture.

Having built lots of SPAs and APIs serving as a backend for them I always feel
that what's really relevant is modelling your data and domain logic (which
tends to happen on a server side) and the UI consuming this data on the other
end. Everything in between – endpoints exposing the data on the backend,
frontend machinery to pull that data into client – seems to be totally
arbitrary and implementing it is nothing short of a grind.

