3 ms·
<Rant> I tried that for 6 months then went back to JS only to discover that within those 6 months Facebook and half of the React community had moved on to ES6,
by ilostmykeys 11y ago
<Rant>
I tried that for 6 months then went back to JS only to discover that within those 6 months Facebook and half of the React community had moved on to ES6, and even ES7, which meant that I just missed half a year of the most important phase in the evolution of JS. Great job, says me. I'm having to make up for it now.
What nudged me out of my love affair with CLJS is when I needed to implement a really simple async pattern in CLJS. Everyone pointed me to core.async (later on someone mentioned the cats library which uses monads etc) It didn't feel right to use core.async's syntactically and conceptually complicated CSP pattern to solve a truly simple problem that can be solved far more elegantly with a much simpler and more general pattern using ES7's async/await.
And now that we have decorators, typed data structures, iteration protocols and a myriad of other tools available to us in ES6/ES7 the only thing that is missing is NATIVE immutable types.
</Rant>
- Skinney 11y ago> What nudged me out of my love affair with CLJS is when I needed to implement a really simple async pattern in CLJS. What? Async/await in CLJS is: (defn async-fn [] (go true)) (go (<! (async-fn))) How is that syntactically and conceptually complicated compared to async/await?
- ilostmykeys 11y agoWhy don't you go further and try/catch that to make it usable in a real app? How do you handle async errors?
- Skinney 11y agoInstall an exception handler on the channel or return exceptions on the channel. The latter is more common. I've written my own macros to make the latter case pleasant (<10 loc), but I believe the go-catching and <? macros from glossop provide the same functionality. (defmacro go-catching [& body] `(go (try ~@body (catch js/Error e# e#)))) (defmacro <? [chan] `(let [res# (<! chan)] (if (instance? js/Error res#) (throw res#) res#))) Used like this: (go-catching (<? (async-fn)))
- ilostmykeys 11y agoCan you expand that to the concurrent scenario? Show us how you implement this simple and very common concurrent pattern with ClojureScript. I've seen stuff that implement this in ClojureScript and it ain't pretty (to say the least) Impress me! :) In ES7: async function fAsync() { try { var results = await Promise.all([asyncOpA, asyncOpB, asyncOpC]) } catch (e) { ... } }
- yogthos 11y agoimpressed? :) https://funcool.github.io/promesa/latest/#error-handling https://funcool.github.io/promesa/latest/#error-handling
- deleted 11y ago[deleted]
- ilostmykeys 11y agoI couldn't find example in the docs for that library showing concurrent async ops with simple try/catch type error handling. So it's still not clear to me how you would rewrite the above shown async/await concurrent scenario using this library.
- mad-mad-beaver 11y agoJust use promesa/all then catch :) Moreover, it has funcool/cats bindings, so you can use promises in mlet and alet macros if you are into monad thing ;)
- ilostmykeys 11y agoOh right, that makes sense but does not make async code organize the way synchronous code does (as async/await sugar enables) but is a fair deal if you don't mind your async code using a different organizing pattern or if you specifically want it to be that way... :) Re: cats Not a big fan of abstractions that don't contribute to code simplicity. What is the percentage of programmer who dig monads? Less than 1% probably.
- yogthos 11y agoThis is a really strange line of argument. While core.async is popular, nothing precludes you from using other libraries such as promesa https://funcool.github.io/promesa/latest/ https://funcool.github.io/promesa/latest/ that have semantics you seem to prefer. Second, ClojureScript has great interop with Js, so there's absolutely nothing stopping you from using a Js library/feature if you so choose. >And now that we have decorators, typed data structures, iteration protocols and a myriad of other tools available to us in ES6/ES7 the only thing that is missing is NATIVE immutable types. It boggles my mind that somebody could see this as a positive. The biggest problem with ES6 is that JavaScript just keeps growing as a language. It has lots of features and quirks already, and more are getting added. This is what you end up dealing with when using ES6 + React (https://i.imgur.com/AjSTP20.png https://i.imgur.com/AjSTP20.png). I think the problem with this is that it adds mental overhead when you're reading and writing code. Something that looks like it might be doing one thing does something subtly different. This leads to hard to debug errors and wastes you time. It also distracts you from the actual problem you're solving.
- ilostmykeys 11y agopromise-a by itsef does not solve callback hell it simply turns it into a never-ending-chain-of-thens but async/await (built on top of promise) does make things easily comprehensible. How do i use async/await in CLJS? More importantly why shouldn't i use something like ESLisp if I am into lisp but want to work with JS features directly? Why would I want to mix JS with CLJS amd require everyone who maintains my code to know both? I'd recommend checking oit ESLisp on github, although they're still working on adding ES6/7 support. To each their own Dimitri :) i gave up on CLJS after it was evident to me that JS is maturing and has copied a lot of the stuff I like from CLJS plus some stuff from C# like async/await. Haskell is cool and so is Elm but all of these will ultimately be copied in pieces by the most dominant language on the web (JS) so it's easier to be on the receiving end of all that goodness as opposed to being stuck in any of those niche languages. Appologies. It's just my opinion.
- mad-mad-beaver 11y agoHow is "never-ending-chain-of-thens" fundamentally different from async/await? It's still the very same code but with different (and somewhat disconcerting) sugar. I've been using promises long before ES7, and it's actually harder for me to read async/await functions and reason about them because they look so much like ordinary functions but aren't. There are useful features in ES6/ES7, to be sure: fat arrows, destructuring, imports/exports. Classes and spreads are useful too if you do a lot of React and JSX. But async/await, decorators and generators are just fancy and questionable ways to perform routine functional stuff one can easily do in shaggy pre-ES5 Javascript. I write a lot of ES6/ES7/JSX at work and CLJS at home and 100% prefer the latter. I want immutable values with destructuring, lazy sequences, suit of threading macros, decent cond|p/case, protocols and whole CLJS ecosystem. I've adapted to ES6/ES7/Redux/RxJS and often even could write code near-identical to CLJS/Reagent/Re-frame/Reagi stack. But it is definitely more painful and limiting experience.