Earlier quoted context omitted.
I personally agree. But the default expectation (and therefore the design) should follow the practices of the language. If JS allows mutations on the objects passed to a function to be reflected on the parent, I believe frameworks should follow this paradigm. And in the end in Gea developers have full control over this, just in the same way they do in real life. `child({ ...obj })` easily solves this, for example, in…
You're using various terms to refer to concepts which are similar but distinct, and it's confusing the issue a bit. > But the default expectation (and therefore the design) should follow the practices of the language Languages do not have practices, developers do. Regarding "idiom": core language features/semantics are not idioms. In programming, "idiom" usually refers to small commonly-used patterns that reside atop…
JavaScript Is Enough
71–80 of 110 posts
Re: JavaScript Is Enough
#72Re: JavaScript Is Enough
#73React hooks always struck me as object-oriented programming reinvented through the back door of functions. We started with pure components, decided we needed state after all, and ended up with magic functions that stash and retrieve state from some hidden context — essentially re-deriving this with worse ergonomics and an implicit ordering contract. Some part of it was the functional language paradigms like immutabil…
You can now use React Compiler and there would be no virtual DOM. Already being used in production at large code bases.
Re: JavaScript Is Enough
#74First, the claim that one gets "reactivity for free" is not entirely true (although the costs may be negligible for many apps). The stores are wrapped in proxies, which lowers the performance of, for example, property access. This is why I rejected the idea of proxies and instead considered generating getters and setters to handle reactivity. This could, in principle, enable zero overhead reads (assuming that all the reactivity stuff were to be handled in the setter). However, this approach fails to account for, for example, array mutations. Thus, I see the point in proxies, but the cost of them can be significantly lowered performance (which may not matter for all applications).
Second, not memoizing computed values (i.e., getters) can also have a significant negative impact on runtime performance, because expensive computations may have to be executed many times. I suppose that caching could be offloaded to the developer, but this could be laborious, at least if the developer would have to keep track of when to invalidate the computation. In, for example, Excel, computed values can be accessed fast, because they are stored in memory (although the added memory usage can become a problem).
Third, you have not addressed async stores or async computed values (as far as I can tell). I will admit that considering async can be quite complicated. However, for better or worse, async is still a key part of JavaScript (e.g., sync alternatives do not exist for all APIs). Thus, the claims "JavaScript is enough", "Zero Concepts" and "You already know the entire API" are slightly imprecise, because async is not supported (although, this does not necessarily matter for many applications).
These three points were the main reasons why I chose not to pursue my similar ideas (especially in the context of computationally demanding applications). Still, I find the idea that JavaScript should be enough for reactivity to be compelling and worthwhile of further development.
Re: JavaScript Is Enough
#75Looks quite cool! I have also considered similar ideas, but have decided to not develop anything. However, there are a few important areas where we have different points of view. My main use cases relate mainly to computationally demanding applications and, thus, runtime performance is quite important. First, the claim that one gets "reactivity for free" is not entirely true (although the costs may be negligible for…
Since Gea doesn't rerender the template _at all (well, for the most part, at least)_, in theory we wouldn't really gain much from getter memoization, mainly because we create proxy observers for computed values that update the DOM in place only when the underlying value updates.
And since stores are plain old JS classes, there's no need for an "async store" concept. Just update a value in the store whenever you want, track its loading state however you want, either synchronously or asynchronously, and the observers will take care of them. If you refer to another pattern that I'm not aware of, please let me know.
Re: JavaScript Is Enough
#76How does this thing run so close to VanillaJS without carrying any extra baggage along for the ride?
I personally don't believe anything can beat hand-built and fine-tuned vanilla JS code, and in the benchmarks we see Gea beating vanilla JS implementation (for example in partial update or swap rows). One reason for this is Gea's compiler has special cases like row swap's to be as minimal calculations and DOM operations as possible. The compiler, also, is evolving to recognize more and more patterns, and compile them…
One random recommendation I could give based on my experimentations on both firefox and chromium
you can attach symbol based custom properties to each such dom node 'class'
and apart from using .matches(), symbol attribute check. this outperforms class based equality checks by a small margin.
very marginal but hey, you are clearly tryharding.
Re: JavaScript Is Enough
#77Earlier quoted context omitted.
I personally don't believe anything can beat hand-built and fine-tuned vanilla JS code, and in the benchmarks we see Gea beating vanilla JS implementation (for example in partial update or swap rows). One reason for this is Gea's compiler has special cases like row swap's to be as minimal calculations and DOM operations as possible. The compiler, also, is evolving to recognize more and more patterns, and compile them…
GJ one your library One random recommendation I could give based on my experimentations on both firefox and chromium you can attach symbol based custom properties to each such dom node 'class' and apart from using .matches(), symbol attribute check. this outperforms class based equality checks by a small margin. very marginal but hey, you are clearly tryharding.
Re: JavaScript Is Enough
#78Looks quite cool! I have also considered similar ideas, but have decided to not develop anything. However, there are a few important areas where we have different points of view. My main use cases relate mainly to computationally demanding applications and, thus, runtime performance is quite important. First, the claim that one gets "reactivity for free" is not entirely true (although the costs may be negligible for…
Thanks for your insights. I was originally hesitant about the performance of proxies, too, but they turned out to be great. The benchmarks ( https://geajs.com/benchmark-report.html ) also show good results. Both in terms of memory and CPU cycles, even though proxies are obviously adding an overhead, it's not day and night ( https://jsben.ch/proxy-vs-object-performance-benchmark-dtxo6 is a good test for this). With a…
Object.defineProperty getter: 82M ops/sec, Proxy getter 32M ops/sec => proxy get is 2.56x slower.
Object.defineProperty setter: 14M ops/sec, Proxy setter: 12M ops/sec => proxy is 1.17x slower.
However, in my simple self written benchmark that compares the time it takes to sum the property values (i.e., getter) of 100 million proxies vs plain objects, the result is that the proxies are 13x slower.
When benchmarking the setting of the property value of the 100 million proxies vs plain objects, the result is that the proxies are 35x slower.
My simple benchmark gives results that significantly deviate from the linked benchmark. Regardless, the relevance of the performance implications of proxies should be evaluated on a case by case basis.
Regarding the memoization, I was primarily referring to accessing the getter multiple times (i.e., not necessarily in DOM rendering), which can cause unnecessary computation in Gea (as far as I can tell). In my envisaged use cases, this could often lead to problems (with, e.g., large data sets).
My issues with async mainly relates to developer convenience (i.e., managing the async stuff can be cumbersome). For example, one can use await in a top-level module statement, but not in a class getter. There has been some relevant discussions about this in the context of Svelte, see, e.g., https://github.com/sveltejs/svelte/discussions/15845, https://www.youtube.com/watch?v=1dATE70wlHc and https://www.youtube.com/watch?v=e-1pVKUWlOQ.
Consider this conceptual example (i.e., async computed value):
store0.url = "...";
store1.res = await fetch(store0.url);
How would this be accomplished in Gea so that reactivity would be preserved (i.e., mutating store0.url would trigger a new fetch)? Is it possible to "listen" to changes to store0.url and handle the async code?Re: JavaScript Is Enough
#79Earlier quoted context omitted.
Thanks for your insights. I was originally hesitant about the performance of proxies, too, but they turned out to be great. The benchmarks ( https://geajs.com/benchmark-report.html ) also show good results. Both in terms of memory and CPU cycles, even though proxies are obviously adding an overhead, it's not day and night ( https://jsben.ch/proxy-vs-object-performance-benchmark-dtxo6 is a good test for this). With a…
On my computer, the linked benchmark gives the following results. Object.defineProperty getter: 82M ops/sec, Proxy getter 32M ops/sec => proxy get is 2.56x slower. Object.defineProperty setter: 14M ops/sec, Proxy setter: 12M ops/sec => proxy is 1.17x slower. However, in my simple self written benchmark that compares the time it takes to sum the property values (i.e., getter) of 100 million proxies vs plain objects, t…
Getters in Gea are designed to be used as computed properties by the components' rendering cycles, and in that, they don't need explicit memoization. I believe users can implement their own memoized computed variables if they require repetitive access—in which case each store's `observe` method could be utilized in updating the memoized value whenever a specific value changes in the store.
And for the async case, for now the compiler doesn't handle this scenario. It could be added, but as you expect, for now the same `observe` method could help here as well to listen to changes on store0.url and refetch accordingly.
Re: JavaScript Is Enough
#80I find it funny that the headline is "JavaSCript is enough" - yet this is a compiler on top of JavaScript that introduces magic and behavioural changes to syntax. How well does this work with testing frameworks? Can this run without the compiler?
A lot of the thinking behind this compiler comes out of the box with Rust. If only wasm worked.