The advantage of using pure functional language for frontend than JS hack

bucklescript
ocaml
Tags: #<Tag:0x00007fc82ff75e28> #<Tag:0x00007fc82ff75cc0>

#1

Hello,
I don’t know if it has been discussed, but I’m curious on the advantage of using pure functional language like ocaml via bucklescript than doing javascript hack like using ramda, hyperscript, tachyon… (they seem reasonable and ‘just work’)…

I’ve been scouring this forum for bucklescript and it seems great, but I’m still at odd with Ocaml’s quirks (ReasonML is non option), I mean about its pattern and advanced features (I have no problem with its syntax), I have yet found its usage for my development, I’m only afraid I’ll be missing something if I take JS hack path for functional frontend development (I’m fresh off the boat learner and willing to invest time, already built production for a year with Vue.js, node, php)

Another contender:
elm: I feel still too much abstraction, I need to feel ‘where the things at’ and ‘organized’, modularized just like Elixir while maintaining high interoperability with javascript and CSS. (there was a time when I dislike the magic of Phoenix boilerplate, because of some parts I couldn’t understand but makes sense when handwritten in Elixir)

Any guidance is very helpful. Sorry if it sounds like a long rant.


#2

You need to consider:

  • type safe language -> means you can catch more bugs during compile time not run time
  • immutable data structure -> don’t mutate state, easier to reason about flow

286f7002.jpg

I assume you could get these somehow not using ReasonML, PureScript, Elm.
But it will be much more work to configure all these libraries and restrict using from team but not impossible :slight_smile:

Logan walks us through what his experience has been starting a JavaScript project in a functional style and using the best FP tools he can get in the JavaScript ecosystem.


#3

What is it that you’re concerned about?


#4

Mostly productivity and unknown interopability with js libs (i.e how to do it functional way, what if I want to implement like ag-grid library on it, etc).

What I’ve been doing mainly small to medium size project so I’ve gotten used to strict typing and checking by hand from lower level although it’s not a good practice for bigger projects.

I dropped react for vue.js because of this reason also, feeling claustrophobic of higher abstraction (maybe because I’m new also).

My second concern is time commitment to learn, it feels like balancing between ‘just works but not too proper’ way and ‘good designed but brain melting way’ :smile:


#5

Do you mean on a language level or a library level? In my case, on a language level, JS loses pretty handily here. On a library level I guess you could argue writing bindings for your libraries (if they don’t already exist) isn’t very productive, but I feel like the OCaml ones are about as lightweight as you can make them. They do require that you know what types everything are, though, and BuckleScript has an unfortunate mini-language (it seems to me) that you have to learn in order to translate the bindings.

It’s all very attainable, though, and I would argue that the productivity you lose up front with OCaml would be gained back from being able to return at almost any point in time and be able to make changes, because you don’t have to hold the puzzle of all the types in your head.

Every once in a while I return to one of my Haskell projects and I’m always surprised how much easier it is to wrap my head around making changes somewhere in the system in comparison to my experience with Elixir:

Granted, my Elixir projects are usually bigger in scope and have more moving pieces, but I still feel like types offload a lot of the cognitive workload.

As for interop in general, I think it’s helpful to work bit by bit and simply sort out bindings first and if a functional interface jumps out at you that you can wrap it in, fine, but using the bindings you have in your application should probably illuminate your way forward. With that said, my experience regarding this with OCaml specifically is fairly limited.

In the case of BuckleScript I think it can be helpful to remember that you’re still fundamentally interacting with JS in the end. If there are a few spots here and there that act like mutable JS that’s fine. If there is a central point that your application is built around it’s likely that this should be functional, but a few usages of a few libraries with interfaces that work just like you would use them in JS doesn’t really bother me.

One example would be bindings that I made for Phoenix sockets; there’s no purpose to these being re-made with a functional interface because what I want to do is push to a channel and register event handlers on it. It’s also not central at all to my application and all the data types on my side have functional interfaces, so I think the risk of ending up knee deep is pretty low.


#6

I think Elm has bad interopability with js. But this is not rule. For example http://www.purescript.org/ has good interopability.


#7

It’s been discussed around. :slight_smile:

In general, much more reliable code (if it compiles then the types are right, plus the compiler can generate better code base on the types as well), as well as the code is much easier to reason about.

What quirks is that? I can describe things. :slight_smile:

Hahaha, I love it!

For Elm this is painful yes, but for OCaml/Reason (bucklescript and js_of_ocaml both can compile to javascript as OCaml backends for note, not just bucklescript) can interact with existing javascript libraries very easily as OCaml has a powerful and simple FFI system (unlike Elm). :slight_smile:

Yeah for bigger projects or where maintainability ‘down-the-line’ is important then you definitely want strongly static typing as it makes dealing with bugs and refactoring code significantly easier and more trustable.

That’s the nice thing about strongly-statically types language like OCaml, they force you to think about your types, so design those first, then your functions just become transformations from type to type. ^.^

Yeah bucklescript gives you ‘better’ interoperability with JS libs compared to js_of_ocaml, but it uses a lot of external attributes to do so, which is… less pleasant (but still better than the alternatives if you need that detailed interaction though).

Yeah this is a big thing! When I come back to a project after a few months it may as well have been written by someone else, and with, say, Elixir it can be quite painful to try to add a feature or refactor something because I don’t know how things are transforming or typed or so as it goes through, where with OCaml the compiler handles that and I just write the code and fix it until it compiles again. :slight_smile:

+1

I have a lot, ask away! ^.^

I can’t wait until webassembly is ‘well used’, everything will just run so much better then. :slight_smile:


#8

Imagine all block chain manning code embedded in webasslebly … :slight_smile:


#9

Thank you for your response, it’s thoughtful for me.

Mostly with libraries. When I first started with web dev, I wanted a quick and dirty solution with CRUD tables, so I ended up with ag-grid and react bindings, then vue, because the needed master-slave grid feature was out of my comprehension back then.

Now I can mental map how most of the features more or less can be built in vanilla js (after cracked open how jquery and node works), although with lack of experience I might encounter unexpected setbacks here and there, maybe because of that I like the raw power of js, direct to the browser.

indeed, with Ocaml it’s so scientific-y, my guess it is still build on old paradigm where global code-sharing was non existent and had to be pegged to something to standardize (ML/research/mathemathic). While nowadays, new programmers like me just take the code from SO or git for granted and as long as they fit the overall program, we declared as worked, but then again bad practice.

This scared me frankly :grinning:, mostly my code right now just carefully frankensteinize someone else’s codebase.

Upped this

Yep, my goals for being functional. But my experience with Elixir is a little different, I quite like the language, especially the pipe operator and ampersand shorthand for arguments (&1,&2, etc), testing and doc features are mind blowing as me being new, it seems direct and concise. If only ElixirScript as mature as Clojure and ClojureScript (Java and parentheses putting me off)

Yes I think I will go with this route.


#10

Yes I watched some lambda days video comparing it with ELM, but it’s so Haskell-y, not a bad thing, only feels more added abstraction, just like reasonML, why not go straight to the core? I’m eyeing more on ‘built just right’ like Ocaml. Maybe for my next experimentation.

@OvermindDL1 Hey, your posts are the reason I wanna try bucklescript! now you’re responsible for thousands of us.:grin:

Mostly with its advanced features like fold, functors, I still can’t see where it can be mapped into building real world frontend because of lack of examples. Scientific language for CRUD interface? To me it still feel overkill (like when the first time I knew the concept of state management in Vuex, whoa, why so verbose?).

This is something I haven’t gone through yet, so I don’t know the pain points right now I take for granted, from the answer it seems true functional languages with static typed are easier to refactor and maintain, should be a good investment.

Do you think it’s a good idea to jump in right now? How about the idea on Ocaml compiler for Erlang so we can have the language to rule them all? (maybe should be on separate topics :grinning:)


#11

Øredev 2017 - Sean Grove - Finding joy in programming

Sean Grove argues that JavaScript’s relatively short “time-to-initial-success” creates a false sense of productivity. Constraints like static typing can help detect some failures much earlier, offsetting the potential increase to the time-to-initial-success that may be imposed by the constraints.


"Universal Reason" by Jacob Bass (Strange Loop; Sept. 28-30, 2017)


#12

As an addendum to what I wrote previously, a mini experience report from the “productive” side (Elixir):

Since roughly half a year ago I’ve found myself having to get into a new code base for contracting work. This meant adding features right away. Adding features to a system you have no prior experience with either requires that it does no more than any other system you’ve worked with and it works exactly like everything you’ve seen before, or it requires you to learn what it’s doing.

If I have to add something, I first try to work out which types are involved. If I’m trying to understand what a function does, I work out the types. This is infinitely harder in a language that doesn’t force you to write types (because we lack discipline) and where types can (but generally won’t) change at any point in time. It’s also exacerbated by nil always being invited to the party even though no one explicitly invited him.

It’s definitely possible to make the discovery of purpose easier in Elixir through out-of-the-box tooling, but it requires attention and work, which are precious resources in software development. I’m more convinced than ever that statically checked types are fundamentally superior for new devs on a project. Anything that clearly allows (and/or forces) you to state intentions and assumptions is what you should be aiming for.

It’s obviously not that types are notated everywhere in OCaml, but they’re trivially discoverable through tooling or through simply violating assumptions or creating new, erroneous ones. This kind of rigor through trivial and consistent checking is worth any amount of upfront lack of productivity.


#13

I think it’s just a case of picking bad examples, but fold and functors are in my opinion not more advanced than the rest of JavaScript. fold is just another name of reduce, like the one you get for arrays in JS, while functors in OCaml are modules that accepts other modules. Among others, functors enable the familiar dependency injection mechanism like in OOP, where you can just depend on the module signature and not the actual implementation (and switch to stub implementations e.g. for testing).

I personally think it’s also not too scientific, as I would argue (which some may object) that Haskell and PureScript is on the more “research” side of things, while OCaml stays in the realm of practicality.

As someone had said in a talk (or Twitter? I can’t remember), we tend to mistake unfamiliarity with complexity. I don’t think functors, monads, higher-order functions, folds, etc. are necessarily more complex than inheritance, polymorphism, SOLID (where it can even be expanded to SRP, OCP, LSP, ISP, DI), singletons, visitors, etc.

One thing that I personally like about these languages is the lack of null/nil values, and instead we have the proper compile-time-checked option/result types. Seriously. Just today I had a post-mortem meeting of a production issue which is caused by mishandling of null values. That’s not fun.


#14

This is in no way meant to be targeted at you, but I think this is an interesting position to hold in a world where Haskell is used more in industry than both Elixir and OCaml together (from my own experience browsing work listings). I think it’s a bit outdated to say that Haskell is primarily a research language and while I doubt that everyone who says it means it in that fashion, suggests that having an evolving language with modern features is a bad thing.

Numbers are rarely meaningful when it comes to the value of a language, but they can point to what people are doing with the languages. While you can’t really say “People are not in Haskell for the research/language lab things”, you can definitely say “There is a significant amount of people (in relation to OCaml) who are using Haskell in industry”.


#15

Quoting from here alone,

Haskell is the purest functional programming language.

Makes me want to check it out, perhaps we could learn it and and apply the principles to any tools out there gradually? Elixir itself not strongly-typed and yet people are here for its OTP. Is it the right mindset?

I’m grateful to know first hand experiences like these, so I’m more or less understood why people are serious about prevention measure.


#16

Reminds me of the discussion here. The “purity” has a certain “elitist” appeal - but it can be a bit idealistic - idealism that can get in the way of day-to-day work. I have no idea how much effort one would actually have to invest to become truly comfortable with Haskell. But the learning process can be valuable in itself - even when the learning process occurs sporadically over a span of years.

Elixir itself not strongly-typed and yet people are here for its OTP. Is it the right mindset?

It’s all about trade-offs. (Static Typing Where Possible, Dynamic Typing When Needed)

The nature of the BEAM and the constraints it is designed against make effective static typing difficult. Alpaca is trying to change that - but who knows if that will ever be in a production-ready state. That doesn’t mean that type discipline doesn’t pay off in Elixir - I think it does. But that usually implies that you need to reinforce that discipline with practice elsewhere.

On the front end the execution environment is fairly rudimentary and transpilation is now commonplace so it seems like a perfect place for introducing sound static typing (apart from all the untyped APIs you may have to interface with).


#17

It’s worth checking out Expede’s Witchcraft library if you want to play around with some of the more ‘arcane’ features of functional programming in Elixir.

There’s also Bartosz Milewski’s course and book on Category Theory for Programmers which I highly recommend. There’s absolutely a lot of value to spending time in the academic side of functional programming fundamentals like Category theory. The first few videos really helped me grasp the compositional aspects of functional programming. I’ve been meaning to put some more time into the book, but there’s so many interesting things to learn and only so much time!


#18

#19

Lol, I keep hearing that. ^.^

Identical to an Elixir fold (Enum.reduce/List.foldl/List.foldr).

Ah the advanced HPT stuff, just think of them as a module transformer, they take a module as input, change some stuff about it (even implementations) and return a new module, this happens at compile-time. :slight_smile:

I built some examples using a much older version (when I was still dev’ing it) of my bucklescript-tea library that you can see (with link to code) at:
http://overminddl1.com/bucklescript/

I…don’t know what that’s about… ^.^;

It is to help maintainability. You have a little bit more up-front cost (though not much with bucklescript-tea in my humble opinion ^.^), for SUBSTANTIALLY reduced bug count and better maintainability later.

Precisely this! :slight_smile:

You really should learn a good strongly-statically-functional language like OCaml very well, even if you don’t use it, because the type-based thinking it imparts on you helps your programming everywhere else. :slight_smile:

Now that Chrome/Firefox/Edge/Safari support webassembly and it has reached a stable standard, I think this is starting to be a good time to play with it, maybe not for something that needs to run everywhere, like on IE, but at least for testing and playing with. :slight_smile:

I keep wanting to write a BEAMVM/Elixir backend for OCaml, I just havn’t had the time yet sadly. It would be so awesome to get done! :slight_smile:

This is SO much easier in elixir if they run dialyzer over their code-base with every commit with no issues, otherwise… >.>

nil really is such a horrible horrible design decision in Elixir, one of it’s biggest I do think. zero-typed values are one of the absolute worst things to appear in a language, and although it’s not a ‘true’ zero-typed value, Elixir uses it as if it is. Notice how about no modern language (short of Go) has a zero-typed value. It is that whole anything can be null problem all over again…

Yes, a ‘new coder on a project’ is just like someone coming in for maintenance on an old project, you have to go through the same steps to get caught up and understand what is going on, and strong static types are one of the biggest things that help that along.

OCaml has a great inference system, so you don’t need to write types 99% of the time, but it still knows what the types are, as do you, based on the code itself, and any IDE that supports OCaml’s merlin (basically a language server before there was a language server spec) will tell you the type of anything you want with little more than a mouse hover or key press. In addition the compiler can spit out the entire complete type interface file of a module as well, and even more. It is a very well tooled system. :slight_smile:

Eh, there’s a slight difference. Fold means to reduce from one direction or another specifically, where reduce will reduce a list of values to a single value in potentially any order (generally whatever it determines to be the most efficient, even if it means starting in the middle for example), this can be important depending on the algorithm you choose.

Uh… no, not at all, I’m not sure how you get that either… o.O

Modules types in OCaml are like an, oh, a ‘trait’ in rust, where a module implementation is like the implementation, and many things can fulfill an implementation, but only when used as a First-Class value and not when directly named.

Precisely this. OCaml was built to get ‘real-work done’ to use a meme, so you tend to be significantly more productive in it (like erlang) to get work done, even if it means you have to use one of the very few escape hatches on occasion.

I honestly think they are much easier… OCaml doesn’t have monads though, but some libraries use them, it’s just not as important in OCaml as it is in languages like Haskell as OCaml is not strictly pure, unlike Haskell (but it does it in a type safe way at least).

Some big language author (Java?) called Null the billion dollar mistake. The zero-typed value is one of the very worst things that someone can put in to a language as it breaks so many contractual guarantees (yes even if documented, because you aren’t forced to test it).

Except Haskell breaks backwards compat routinely, and they do so on purpose (their own admission). Haskell plays with lots of styles and plugins and extensions, it is designed to be exclusively a research language. You ‘can’ use it in production if you keep to a specific version, but even the authors admit it should not be.

Except Haskell’s type system is incomplete in capabilities. If you happen to use, oh, the GHC compiler then you can setup a variety of extensions and plugins to fix some of those, unlike languages like OCaml where you can entirely do anything if necessary, including exiting the safe area (which you should never do) and where the OCaml authors specifically pick those things to add to the language that give the maximal usefulness.

All of expede’s libraries are awesome, should play with them all. :slight_smile:


#20

That is definitely true, I stand corrected. What I meant was that OCaml was no more scientific than Haskell, but I think it came out wrong. Thanks!

Eh, but that’s one of the ways (hence “among others”) I’ve been using it for. Indeed putting it that way seems to undermine the power of the module system, but I think it’s nice to know that it can be used to do something familiar. E.g. if I have:

module Handlers (Todos : Todos.S) = struct
  open Ezjsonm

  let todos_list_handler () =
    match%lwt Todos.get_all () with
    | Ok todos ->
      Lwt.return @@ `Json (list (fun (todo : Todos.todo) ->
          dict [("id", int todo.id); ("content", string todo.content)]
        ) todos)
    | Error Todos.Database_error ->
      Lwt.return @@ `Json (dict [("error", string "Database error.")])
end

While the real Todos module connects to DB, I can switch it out with a stub module satisfying the Todos.S signature when testing to only return predetermined results.