The JavaScript ecosystem evolves at a breakneck pace. Just as you get comfortable with a certain technique, a slew of new methodologies emerges. So...
For further actions, you may consider blocking this person and/or reporting abuse
Thanks for writing about Effect. I do really love the premise of Effect! And I do like your writing style.
But after having checked it out and looked through the code, I feel that you're comparing apples to oranges. (Adding that I don't think using Promises in a non-parallelized setup is a fair comparison. Plus, I would love to see benchmarks that support your claim that it's slower. [This was in the initial version.]) Especially considering - as I understand it - Node handles IO in separate threads while all simple/regular computational work is done in the main event-loop thread. From briefly looking into the code, Effect uses a different mechanism to achieve its effects (over Promises) that hooks into the main event-loop. (Which is why you only see one Promise resolving.)
That said, I do really appreciate the effort you've put into this article and I look forward to playing around with Effect when I have some time. And I really do hope that you keep on writing! (I really do! It was actually a great read!) Thanks again!
I did a quick benchmark and the least to say is that I found interesting results. I confirm that simply putting "async" makes the program way slower. However, it looks like it might be even slower with Effect.
I suspect they might be using iterators which might be slower in JS.
Doesn't change the nature of my argument about colored function, and that Effect is pushing for good patterns. However the part about performance gain is misleading. I removed it for now while I investigate further.
Thanks for reminding me to always double check my assertions!
No problem! Like I said, I tried to be constructive because of the knowledge event horizon - yours and mine - and I did actually like your writing style and didn't want you to be discouraged.
I only recently encountered the coloured functions description and I fully agree with the premise of good patterns. The pattern used in Go also appeals to me. The problem of inconsistency in returns is a pretty universal one in that regard. The fact that I actually spent more than half an hour trying to figure out Effect and how you got your result (AND that I responded) should speak to that! :-)
From what I could tell from briefly looking into it, Effect has its own internal scheduler (at least for some aspects) and uses mechanisms that directly tap into the event-loop (setImmediate/setTimeout).
Appreciate you putting in the extra effort with the benchmarks!
There is no part of me that understands why people seem to think that Typescript, an abstraction layer library written in JS is going to somehow perform better than just the native JS is capable of doing. Even async is syntactic sugar spread across the Promise interface.
This is like saying "my Ford F-250 is slower... than just the F150 I loaded into its bed would be alone!?" My ghast... it is flabbered. 😐
Whether one likes or loathes TS, I think it's reasonable to assert that we can ALL agree it's not intended to offer performance gains of any kind. Its sole and exclusive role in the JS ecosystem is to facilitate (no, to very-opinionatedly-enforce) a specific programming style. The argument being that, for those who see the benefit in same, the overhead is WORTH it.
It is as a consequence of this understanding that I am vehemently-opposed to the inclusion of additional runtime functionality. If they have a great way to obviate "colored" functions or whatever, fine. Release a library. Let people elect to run it. But TS is supposed to be TYPE ENFORCEMENT for JS (a loosely-typed language).
The second you start adding methods that do not exist in JS, you've perverted that purpose. Now people will be UNABLE to seamlessly switch between, because the agreed-upon toolbox differs. It's like randomly altering an API endpoint.
Mark my words here: this is a bad decision.
I think you completely missed my point. To be honest, I am a bit confused by what you are saying.
I was highlighting interesting patterns that are technically completely feasible in pure vanilla JS: the duality sync/async, returning errors instead of throwing, strongly typed primitives, IoC using tagged interfaces...
It appears that the Effect library has implemented all of that, hence the highlight.
Just adding
async
in front a JS function will make it 10 times slower. Effect don't use Promise. It has its own async runtime mechanism. So the question about performance is actually interesting.For the record, here is the result:
And the code I used to benchmark:
Not surprising at all, since the only way to achieve "non-colored" functions is by making everything async, which seems to be what Effect does.
But it's important to note that this is not a relevant performance benchmark in general. Running everything at once is always going to be faster vs slicing up the computation, but in reality you'll have other concerns such as not blocking the event loop (either in node or the browser), allowing other queued tasks to run etc.
Thank you for posting those!
Very good point! I wanted to do the benchmark actually. I promise I will do it asap and update my post.
Disclaimer: I am the author of Effect.
Regarding benchmark it is safe to assume that Effect would be the slowest alternative when compared to any non-boxed code and to JIT optimisable code (e.g. a fibonacci over Promise), which pretty much encompass all the possible micro-benchmarks.
Reality is a bit different from micro benchmarks though, performance issues in JS applications hardly ever come from sync computation but rather from sub-optimal concurrency, given that we mostly write IO-bound apps (e.g. calling databases, apis, etc).
What Effect gives is declarative structured concurrency plus great observability, which will help you spot & fix your code bottlenecks quicker than any alternative.
That said even though Effect will always be slower to non-Effect there are still folks who render their apps at 120fps while using Effect on the rendering happy-path, so I doubt that Effect will be the bottleneck in a specific flow, happy to help with debugging any such case :)
Thanks for the article, it is a great writeup!
THANK you.
Finally, a voice of reason (and from literally THE most qualified person to speak it!).
Personally, I don't really have a dog in this fight either way. Use your tools to most effectively GET THE JOB DONE. If you don't LIKE your tools? You're. A. Programmer. FIX that affront.
But to hear the author stand up and say clearly and concisely "this is what it was made for, and if y'all insist on bullying it into something beyond its intention you're missing the point" is refreshing as hell.
Kudos to you, m'man. Both for putting something out there and for being entirely rational about it. Mad respect.
That's literally why I removed the part about performance from the article.
This sentence might be the most meaningful one in this whole writeup. Though I'm not sure you meant it as such.
I say this because all three: Coffeescript, Typescript, and Effect have a similar purpose and dynamic. My hope for both Typescript and possibly Effect is that they too go the way of Coffeescript.
Coffeescript was created at a time before the modern age of JavaScript. It set the groundwork for many of the improvements that were formalized as part of ES6. It 'quietly faded away' because it was no longer needed. (Though not entirely true as it does feature niceties not in vanilla JS)
Typescript could end up following the same path. Proving that there is something missing from JS that people really do want and pushing forward the inclusion of that in vanilla JS. Typescript as a language could well end up 'fading away' as well.
I haven't played around with Effect yet but I listened to a fairly extensive interview with one of the major players (on Syntax I believe) and he made a compelling argument for its approach. It might well be a library that demonstrates a paradigm that should be supported.
I'll be interested to see what happens with it. Thanks for the writeup.
I like what you say! Not necessarily what I had in mind but I totally agree. Reminds me of the proposal for types (without any compiler or toolchain though) in vanilla JS. Typescript should disappear when Javascript swallows it.
This article showed up on my chrome recommended cards, and I had a look until some point as I am not a frontend developer, I use PHP/Laravel, and I know JS, but also know some C#, Python (a bit) and Rust (a bit)...
I cannot understand why JS is not upgraded... You needing to do all this crazy stuff that was solved ages ago in a lot of other languages... Why can't the JS concortium finally upgrade JS to a "real" high level language like other languages?
I see the community, time after time, re implementing basic stuff... I would really love to see TS already integrated into JS natively... And more...
Long story short: browser wars. That's why we can't have already a language natively work in the browser that is compatible with JS, but is designed and tested well.
You can come up with anything, but if Google, Apple or Mozilla won't implement it, it won't happen. We are still plagued with language features that only work in 1 special browser only.
In my opinion JS and CSS are old enough to be replaced with language purpose-built for scaling enterprises applications: you have all those years of high-usage to know what features should be implemented.
So... your position here is: "I say we break the totality of the existing Internet in favor of a slower, still-ocassionally-buggy alternative that is itself running on the original base you're trying to do away with"?
...and for reasons that amount to, "because everyone should have to code like me, because it's easier for me to understand that way!"?
I have that about right?
Yeah. Good luck with that.
Not entirely sure why you seem to take this abrasive stance towards folks who are simply commenting about the state of the world as it currently is. I think we all feel the frustration with the system as it is. No need to shoot the messenger for it.
Because, yes, the browser companies are effectively gate-keeping progress. But at least nowadays we have more direction through ECMAscript. And yes, we don't really have any great alternatives. (ActionScript could've been great for this, IMHO. Java was great as a concept but ultimately carried too much of a resource burden to make it really viable for adoption on the level that JS could.)
Should we make C#, Go, Erlang, Haskel, Lisp, PERL, PHP, Python and Rust compilers in the browser so that we can extend the ecosystem with all the languages we desire? (We might as well build a WASM runtime C/C++ compiler while we're at it.)
And at the same time, transpiler optimization and run time compiler optimization also haven't stood still.
Various compilers get optimized all the time.
And it's not like WASM is a viable alternative at the moment. Not without taking a performance hit.
So, I am not entirely sure what issue you're exactly trying to get at?
I'm also not sure what Nerdy Deeds wrote. From other comments it seems to be a person not getting what TypeScript is for.
My comment was about the lack of choice; you can't get a more performant language, you can't get a higher level language: you have JS and WASM. I contrast it with any other operating system, where you have a huge array of languages.
My advocacy here is for understanding the following:
Someone give this man a microphone!
I don't think Effect solves colored function problem in your example: you just added another type of functions that return Effect instead of Promise. Of course, we can run effects from regular functions, but we also can do that with promises (but you have to handle the results with .then() and .catch() if you care about them). Or we can get rid of sync functions and promises altogether, leaving only effects, but without effects we can leave only promises as well. I don't think leaving only red functions is the solution to blue/red problem.
BUT(!) Effect actually solves this problem the other way: you can start an effect from any regular function and forget about it, letting another fiber (goroutine equivalent) to handle the result, so a "red" function doesn't change the color of a "blue" function.
Fair point! I'll update the article.
Hmm... and how it is not the case in standard javascript? if you call an async function in a standard function (which is absolutely possible) it will be run in the default event loop (in micro-task-queue) which is pretty much fire and forget. What is the practical difference? If I want to do something with the results, I could easily wrap the call with some async queue function and that's all.
Yeah, you are right. Seems like effect doesn't solve red/blue problem at all.
Yeah, touché. You can technically manage a Promise inside a sync function.
Quick experiment of thought: what if we'd just convert all of our codebase to Promise ? Promise states are hard to keep track of, hard to cancel, you need to catch the error, they have eager evaluation... Also we would still have to use regular functions because of standard methods like let's say
Array.filter
whereas Effect provides standard methods to use both sync and Effect functions.So while I agree that you cannot completely solve the function coloring problem in JS, I still think that Effect helps us closing the gap even if that difference is thin. I will update the article in that sense. Thanks for the comment!
It's a shame we are forced to use this farce of a language where problems that have been solved for decades have to be continually reinvented.
I have good hopes for Rust with wasm on the frontend! Also keeping an eye on Gleam which can sort of compile to JS.
While Effect is heavily influenced by ZIO, as you said, the error handling you described here is a common pattern of handling error without throwing an exception. It is not from ZIO. In Scala, it is handled by
Either
and its subclassesLeft
andRight
One thing to note here about async programming. The keyword
await
is to force a certain timeline to happen. You can useawait
strategically, when you do need the result as input for yet another async function. I don't know howEffect
is implemented, but I think if you usedPromise.all
well in one of your examples you would have had a similar timeframe.(Note, that in the effect Fibonacci example you wrote
n === 1
which does not seem to be correct.)I liked the beginning, I'm not sure JavaScript needs fixing though, the challenge I see is how many things try to hide the power of JS instead of embracing it.
This looks like a lot more layers and I'm mostly excited about the idea of composability, which usually involves simpler components than this. I personally prefer a for loop to the forEach function, which shows how much of native JS I prefer.
if you write a follow up about why you think CoffeeScript didn't pan out, and why TypeScript reigns supreme in a lot of ways, I'd be interesting to read that.
for example: I like the divide by zero handling idea, not 100% sold that the function signature is the right place for it though.
Thanks for posting it was an idea generating read!
Instead of band-aiding JS maybe it's time to just use a real typed language like C# or Java.
Like C# or Java haha, thank you for the good laugh!
And you find this funny why? Typescript is basically modeled after C# but far more difficult to master.
:)
True that. JS community wants some problems to not be fixed. So that the community can keep reinventing and creating contents!
Amen. Give THIS man a microphone.
Come one can you stay on Java...
At this point it looks like Java. And probably will have the same problems as Java has.
Verbose 200 files for one pitiful function.
Javascript is frontend.
You can use in back-end python or w/e.
But you really want to do "typed languages" in web? You mean like Java did that was so ungodly bad that they had to come up with Kotlin just to band-aid the problems?
And Java actually woke up from 1980 and put the long wanted features in?
If it doesn't fit... just use any other language.
(More a generic comment 🙂)
No, it wouldn't.
Languages are tools. Each one is for a specific context, a specific environment, to solve a specific problem. Simplicity is also a virtue. Don't overdue it.
Use the right tool for the right job.
imho🙂
I really don't understand this "color aversion". I think it's a complete misconception. Even the very axiom of the "issue" is trivially false. There are no red and blue functions. There is only one kind of Function object, some of which returns a specific type of object called Promise. That's all. Of course you can call any function from any other functions. Please don't confuse people!
The whole problem about Promises has nothing to do with "function calling" it's the issue of the hidden internal state or context. If we want to colorize stuff, we should have a whole rainbow of colors for all functions returning objects with internal state/context !
Async functions (which are basically promise-returning functions) are inherently not pure. What you want to manage with libs like Effect is this impurity and not some fictional color. One standard way to deal with impurity is to wrap up the context with some type, this is what Haskell does with monads and vanilla js (and many others) do (in this specific case) with Promises. The "color" of the function is nothing else than the context manager (or monad) of the impure concept (ie. the asyncron queue manager) and that's it. Therefore there could be yellow, purple and pink function too, but I think it's much better to understand the concepts of purity and static (stateless) functions and how to use them.
Related: functional reactive programming. See rxjs.
It's observer pattern and functional programming on steroids (as early as 2016).
Just to put the church back in the center of the town : Rx , another thing borrowed from C# (like async/await and a lot of other constructions).
Looks good, have to give it a try. Thank for sharing it.
What is the gain over state machine (xstate) ?
Btw, thx for your great work.
Great read!
Great!