Front-end frameworks: Flame, Concur, Halogen or something else?

@natefaubion i really appreciate your feedback. However, I fail to understand one thing. My reason for wanting to explore PureScript is that I was generally not satisfied with the “impurity” allowed by certain other languages e.g. ReScript. When people mention pragmatic, imperative, OOP it starts itching… If i was to start writing in a more verbose language such as PureScript my whole motivation would be to write as purely functional as at all reasonable, if we also give just a little bit of weight to productivity and performance of course. However code quality for me is largely adhering to the functional principles as much as possible… Many other things plays in as well of course. I know code quality can start a huge discussion and is very subjective, but at least to me I’d not expect to hear pragmatism from PureScript developers… I thought purity would be more important for this language because there’s so many mixed, messy and pragmatic languages out there.

1 Like

Purity is orthogonal to OOP vs functional. To be clear, we should breakdown why Halogen gets the OOP criticism.

  • Halogen has a concept of a “component” which is defined as a record with some fields (render, initialState, eval).
  • Halogen component state is existential (encapsulated and invisible to the outside world).
  • Halogen components can be embedded in a parent component and that parent can send messages to the child, and a component can bubble messages to the parent.

That’s it. Notably, this has nothing to do with: purity, unconstrained effects, mutation, referential identity, inheritance, subtyping, etc. Components are a unit of encapsulation/abstraction, and a way to get data into and out of it.

If you look at a typical TEA framework in PureScript, what do you usually have at the root?

  • The concept of an application, which is defined as a record with some fields (render, initialState, update)
  • The application state is usually not existential because there is only one.
  • Mounting the application usually gives you a way to feed messages to your application.

At a high-level, the only difference here is that TEA does not provide a unit of encapsulation/abstraction. You build UIs by writing glue code between a conceptual parent and child if that’s your thing, and that’s totally fine as it’s a different tradeoff. It may totally be to your taste to eschew some attempt to provide that for you, and stitch your application together yourself (simpler types usually). You could write a Halogen application using only a single root component, and you basically just have TEA.

However, at no point in this overview did the question of “functional” come up. If your primary concern about “functional” is purity than you can use either! Halogen is just as pure as TEA. You can write a component in Halogen and enforce that it has no effects at all (other than ambient component effects). You can also abstract over your effects and ensure that it only uses effect interfaces, restricting effects locally.

When I say “pure OOP”, that’s really what I mean: there is none of the usual baggage that comes along with OOP languages and design specifically because it’s embedded in a purely functional language. Both Halogen and TEA are just MVC, with largely equivalent expressivity. So in my mind, using OOP as a criticism here just doesn’t hold water. Note, I’m not really here to convince you to use Halogen or anything (I don’t personally use Halogen professionally). Just that there are other much more interesting considerations to explore when picking something like Halogen or Flame (for example) for professional use, and I wouldn’t worry about the functional moniker.

Hope that helps!

5 Likes

Since you say you’re not using Halogen professionally, what are you / would you be using and why? You seem very experienced so it would really be interesting to hear your opinion on Flame and the other front-end frameworks for building large Single-Page Applications.

It sure does. Thanks!

We have a large PureScript+React codebase at Arista NDR. For us in particular, there was already a very significant React application (written in plain JS), and interop was a hard requirement. Decision made! Over the past few years all new development has been in PS while the old JS portions of the application were left largely as-is or replaced when needed.

So I don’t think there’s a one-size-fits-all here and I can’t really make a recommendation for a specific library. You have to consider:

  • How much knowledge do I have as a PureScript user? Do I know how to fix things if I run into blockers?
  • How effectively can I onboard other developers to my project?
  • Is leadership (or a client) willing to invest in a potentially niche UI framework?

Using PureScript in a professional setting will likely require some compromise to avoid blowing the novelty budget. As a niche language, PureScript itself occupies a large part of that budget. In some cases, adding a whole new UI library or paradigm to the mix may be too much, and that’s OK.

6 Likes

If you are new to FP, then I’d recommend Elm as a starting point for experiments. Because it has a “standard” way to start, least amount of decisions to make, very simple language with least concepts that you’ll have temptation to learn. Then if you are comfortable with that style, but feel some lack of abstractions to be more productive you’ll easily continue in PureScript and will be able to make reasonable choice of framework.

1 Like

Thanks @stiff , but I already ruled out Elm for a number of reasons. I don’t like the fact that Elm was made so specifically for the frontend. I don’t like how it dictates that you build apps using the Elm architecture. Imo a language should not be that opinionated an locked on implementation details to that extent, but be more flexible. Also i don’t see a bright future ahead for Elm as the author had been focussing on his next language for more than 3 years now. There are many more reasons why i don’t find it interesting compared to PureScript. Interoperability with js packages is one more thing, and the PureScript core team and community gives me a reason to believe PureScript will be around much longer than Elm.

I’ve already decided I want to learn PureScript. For long I’ve disliked how most languages are mixed languages supporting both OOP and FP and imperative and declarative ways of writing code. PureScript seems to be for people who are interested in writing better code while still allowing you to be productive. At least that’s the impression i get after my first week with PureScript.

6 Likes

If you already made up your mind then surely go with PS, it’s a very nice and flexible language. Compared to Elm, JS interop is indeed way less strict and limited. Initially I just thought you were looking for something for quick and easy start to get some hand on experience, but now your point is clear.

1 Like

I don’t really maintain this anymore (it probably still compiles fine), but if you want a reference for a TEA setup that can be read over in a weekend, you can also check out GitHub - natefaubion/purescript-spork: Elm-like for PureScript which I created to feel like an idiomatic PureScript TEA variant. It’s all in PureScript and shows how you can implement the nitty-gritty details without dropping into FFI.

2 Likes

Are there any comparisons on efficiency in change detection, redraws, etc. between React and Halogen? Let’s say you were to effectively go with the "Let’s do TEA in Halogen/purescript-react-basic-hooks (+ useReducer), would one hold an advantage over the other in terms of VDOM efficiency, smaller redraws based on localized state differences leading to redraws of a sub-tree in the HTML, or anything like that?

1 Like

So it’s just as a reference? Looks super clean and simple, but tbh I’m not specifically looking for what’s easy, but the frontend framework the most experienced PureScript devs are using or recommending for new projects that potentially can get big and complex. So it’s more what’s powerful and promotes best practices (and well maintained ofc).

Why did you stop maintaining it, if I may ask? Is it just to serve as an example on how you can mimic Elm to build a minimal framework on top of PureScript?

And just to be sure, by TEA framework you basically just refer to being productive (productivity framework), right?

1 Like

I think TEA is used here as the elm architecture - it’s the app-architecture style often called Model View Update as well - where you have some kind of Model (that holds the apps state), a View to display a model (usually as HTML in the browser) and a Update that (well) updates the model due to some actions/events/messages that happened.

The framework part usually handles the details (storing the model, updating it via Update, displaying it, details concerning sideeffects etc.) - most frameworks are more or less in this style (including at least the old style of React/Redux).

I think Elm made this “pattern”/“architecture” popular for functional-oriented communities so we stick with TEA or in some cases “elmish” :wink: - Most “mainstream” developers seem to call it MVU though.

3 Likes

Hey sorenh, welcome. I hope you find PureScript fun and as rewarding as I have!

I’m on a team that uses Concur in a production project and we have recently started using Halogen for another project, both commercial boring line-of-business apps (but quite interactive!)

I initially shied away from using Halogen, mostly because the type signatures involved in making a Halogen app felt complex and confusing. But I think Halogen had a refactor to make some things simpler (especially components) a year or two ago, and it’s a lot better, plus I got over my fear and just used it.

I have to say it’s been very pleasant, even in an application with a few sub components. I also learned It’s not necessary to understand Halogen’s entire type stack to use it, so maybe the types haven’t become simpler but my attitude has improved.

So I would say, unless you have a good reason to use something else: Halogen is the most used, best supported UI library for PureScript (IMO).

As for Concur, it does have a bit of a not-production-ready vibe to it. However, we are using it in production as we have a use-case that Concur works particularly well for, and it’s fine!

How that not-production-ready vibe manifests: you’ll find corner cases that no-one has thought of, for example there’s no obvious way to have widgets communicate across the app with each other, unless they return values all the way up the callstack and sync at a higher level, which is often not desirable.

But with every library someone had to be the first to figure out those corner cases, maybe that someone will be you? :smiley:

3 Likes

I thought the Wire API was made explicitly for what you mention above. Did you try it? Example from the Concur React repo below:

2 Likes

Nice, I’ll give that a try, thanks! I see in our codebase we’re not using that anywhere so it’s likely we just missed it.

As someone who has worked on a Halogen app sporadically for the past few years, I can recommend it. It’s fully featured and can do pretty much anything you need. One thing I don’t like about it though is that defining components feels ceremonious, which is why I highly recommend Halogen Hooks. It’s still Halogen, but nicer.

Personally I just have a “template”-file for a component lying around which makes it really easy to reuse.

I’ve used Hooks too for a project and while it did work out great I found that it’s easier to get spaghetti-code using hooks - “normal” Halogen with it’s TEA approach forces you in a more obvious structuring of the component (mainly because you have the eval/handle functions for the “logic” instead of being able to stick it more or less right into the view part.

Also I found that I tend to use nested functions a lot with hooks (to remove the need to pass along parameters) which is great but sadly you get no type-inference support in the editor with this (something that the Haskell LSP really does a great job with btw).

1 Like

For the parts of the app that are in Concur you could just run all components that you want to talk to each other in the same StateT monad too, global state essentially.

1 Like

does concur play “nicely” with SateT? I’m asking because AFAIK Halogen does not.

I have used it analogously to local state in ReactJS, and have experienced no problems. What problems does Halogen have with StateT ?

There is a Issue where it is discussed and you usually get warnings like this

To be honest that’s from a few years back and maybe current versions don’t have that issue but by now I don’t even think about using StateT instead I either use Vars or something like the store

1 Like