Live data from Hacker News

JavaScript Is Enough

geajs.com

71–80 of 110 posts

Re: JavaScript Is Enough

#71
post #55

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…

[dead]

Re: JavaScript Is Enough

#73
post #52

React 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.

You can and you can't. There's still plenty of very popular libraries that don't behave correctly with it. That's more on the libraries than on the compiler but that's the current state of things.

Re: JavaScript Is Enough

#74
Looks 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 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

#75
post #74

Looks 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 proxy, you can set a property 25 million times per second (on my M4 Max machine in Safari) with only 4% perf loss vs defineProperty, and Chrome is about half the perf with 20% loss vs defineProperty. So, still, 12.5 million setters per second is pretty good. Of course if your use case demands more performance, nothing beats a hand-optimized vanilla JS code.

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

#76

How 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…

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

#77
post #76

Earlier 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.

Thank you! Very interesting insight—I'll have a look.

Re: JavaScript Is Enough

#78
post #74

Looks 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…

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, 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

#79
post #78

Earlier 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…

Very interesting benchmark results... well, I guess that's proxies for you.

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

#80
Not to knock on the project - it's certainly interesting.

I 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.

Post reply on HN