Hacker News new | ask | show | jobs
by Meai 3354 days ago
Seriously, your own homegrown garbage collection inside the js runtime? I looked at React the first time it came out and aside from the insanity of using xml mixed with javascript or some kind of pseudo js, it was waaaay too complex. I dont know but it seems crazy to me to write applications like that, it makes xaml look decently simple.
6 comments

I still firmly believe riot.js (http://riotjs.com/) is the best "react-like" tool even though it's almost entirely unknown (sadly) and its website/PR/general presentation is a bit janky.

It's essentially a very very tiny, minimally opinionated structural layer that lets you build html components (called "tags") using almost entirely vanilla JS. It inverts the JSX paradigm: where JSX is "html in the middle of your code", in riot the markup is primary and the code is a supplement to it (expressions in the markup via templates/mustaches, additional tag-specific script added outside of the markup if desired, tag-specific scoped css) so there's no JSX insanity.

It's like a much leaner react/vue, and frankly I love it. It's entirely minimal and you can bring in any library you want to use along with it (e.g. jquery for ajax, redux if you want...). It has virtually no cognitive load (just looking at a sample "tag" file for 2 minutes gives you ~80% of what you need to know), you just pick it up and work with it and just occasionally peek at the docs if needed.

I'm a huge fan of the "minimally opinionated" approach. The fewer idiosyncrasies and custom abstractions in tools, the more productive you are (I'm looking at you, angular!).

Several points of agreement here, and now I'll have to check out Riot (which I remember seeing around here a while ago).

But I think that

> html in the middle of your code

is selling JSX a bit short. Tooling and coupling aside (and I agree those are strikes against it), JSX creates a pair of mutually-recursive, formally-defined languages, which you can switch between freely and frictionlessly. I've never seen this before, not even in lisp, where quoting/unquoting is bad enough at a single level.

This—the ability to compose languages—is extremely powerful in general. Even if you don't like JSX per se, I'd bet there is some set of languages that you'd like to be able to use this way. I'd look at the "controversy" around JSX (and Babel and the React dependency) in this light, as a learning experience.

For example, JSX is really just a variation on EX4, which has been around for much longer. A number of "external" factors have put JSX over the edge (of mass adoption), and these mostly have to do with React's popularity. By the time I capitulated and decided to try React, I found that I already had tooling support for JSX, even though I was pegged to Babel 5.8 for reasons.

I think this is the principle behind OMeta: we should be able to iterate on language features as freely as we do on application features. We ship applications, why shouldn't we ship the languages, too? (Of course OMeta came out of VPRI, and Alan Kay's view is that we could just ship the whole dang system!) Anyway, from that perspective, JSX is no more "insanity" than some of the things we do to work around the rigidity of languages-as-silos.

Thanks for the insightful response. I think you make a compelling case, and it's something I'll be thinking about (I've gone back and forth regarding what to think about JSX).

In the specific use case of React and Riot, I feel like it's more natural to have markup be the main structure and code to complement it, rather than the other way around, but I don't feel that strongly about it and I find React's approach is still not too bad (imho of course).

I tend to get a bit of an "overly academic" or "cargo cultish" sort of vibe from designs I consider overwrought, and I had a little bit of that sentiment about React back when I worked it, but really it was not a very strong feeling and I'm convinced React is pretty great.

The one that really gives me that vibe is Angular. No offense to anyone who likes/uses Angular, but I view it as a criminal case of abstraction run amok.

>we should be able to iterate on language features as freely as we do on application features. We ship applications, why shouldn't we ship the languages, too?

Time needed to learn and refactor :/

I also found Riot very practical, mostly because I got up and running very quickly. I had a well-structured Riot app done faster than grasping all that ReactJS boilerplate.

And this was possible even though the Riot documentation was sub-optimal in some places, to say the least - the holes in the documentation were compensated by the fact that most things are simple and straight forward.

I don't know how good this concept scales to huge applications, but I can confirm that writing a non-trivial SPA in Riot was a charme.

Neverthelss, I do miss some things the Riot for the overall architecture and information flow. But I learned that ReactJS doesn't have these either. As with React, Riot should be combined with Flux, or a lightweight alternative such as Redux.

>Neverthelss, I do miss some things the Riot for the overall architecture and information flow. But I learned that ReactJS doesn't have these either. As with React, Riot should be combined with Flux, or a lightweight alternative such as Redux.

As long as you remember that you're doing Model-View-Whatever, you can structure a riot (or react/vue for that matter) application fairly lucidly and without too much friction. You want the application state (~Model) to reside in a separate container, and the riot/react/whatever custom tags (~Views) should be fairly lean and strive only to display and trigger operations on the state (i.e. either call functions exposed by the state object, or trigger/listen to state events), while storing as little state as needed locally. If you're lazy like me, you can make the app state container a global - otherwise just pass a pointer to it to every tag (Flux).

Redux helps with the minimization of local state by emphasizing pure functions, and thus encourages the required minimal state to be passed in as function parameters when needed (and in the localest scope needed). That's really the genius of it, imho - functional purity keeps the state tidy.

Riot's (optional) solution is an "observable" functionality which can be attached to any object (e.g. the state container itself or a child thereof), and tags and other objects can then listen to events on those objects and update themselves accordingly (pretty classic pattern - but being minimal and "vanilla" is the point of Riot anyway), and so I find myself using this and not going with Redux, for the sake of productivity, even though it's a little bit sloppier than Redux.

I found and loved Riot, too. Even used it to build a medium-sized application. At a time when React was in flux (pun intended, I guess) it was the first implementation of the custom component model that made me go "ah ha!" Mostly because how fast I could be useful with it.

The challenge I think for Riot is just that the community never really developed around it. As my friend always says, when you pick a technology, you are picking a community, and the latter may matter more in the end.

I find Vue to to be the best blend of the two. Great docs, great community, and as powerful as react. (Don't let the declarative templates fool you, everything compiles down to render functions and you can even write JSX or even hyperscript if you want to.)

Vue doesn't quite have the React ecosystem but in some situations fewer choices may be better, as examples, boilerplates, etc, seem to have more in common rather than less.

I feel you're being disingenuous here. They're just talking about automatic cache eviction, which wasn't possible/trivial with the previous version of Relay.
I agree with you. But given the announcements own terminology, I think the misunderstanding is understandable.
I think the terminology is fair, given that I believe it uses a reference-counting mechanism to determine whether cached data is currently being used by a mounted component. But it's not quite as crazy as "JavaScript's GC sucks, we're inventing our own".
> homegrown garbage collection

You could say the same about shadow dom rendering: "Your own homegrown DOM renderer?". But in practice, it has a good reason to exist (performance vs. real DOM) and nearly zero usability issues (it is completely invisible to the developer, "it just works").

If they hadn't considered "garbage collection" (cache eviction, really) then it would have been seriously difficult to manage from outside Relay (and would partly defeat the point of using it).

Hey! I'm Joe and work on the Relay core team.

These are good questions: why does Relay Modern have garbage collection? Is that just a fancy name for cache eviction?

Let's put aside naming for a moment. Relay stores GraphQL data in normalized form, as a map of global identifiers to records. Each record has an identifier, type, and map of fields to values. Relationships between objects are expressed as fields that "link" to other records. These links are expressed as data structures - an object such as `{__ref: <id>}` - as opposed to direct references to the objects.

Using object references would mean that Relay could in theory let the JS runtime do garbage collection: except that the runtime would only see a cyclic graph of objects for which (typically) at least one root object had a persistent reference (the record corresponding to the root of the graph). In other words, it would do its job and retain all records in memory since they would all be (in)directly referenced from the root object, which would have to be referenced by Relay in order to access the data.

Relay, however, has more knowledge than the JS runtime does about how this data can be accessed: it can analyze the currently active queries against the object graph to determine which records are required to fulfill those queries. This is what the garbage collection feature does: remove records that may not be referenced by any active query.

Note that this has some aspects in common with standard garbage collection in programming language runtimes. There is a mapping of identifiers (memory addresses) to values. Each value may contain links (pointers) to other records (blocks of memory). Because the graph has cyclic references, standard cache eviction strategies - LIFO, LRU, etc - don't necessarily apply as they might evict data that is still referenced.

I hope this helps shed some light on this feature. Questions and suggestions (PRs) welcome!

This isn't JS runtime object garbage collection. As others have said, it's cache eviction. Bad naming, perhaps.

But if React is too much for you (tiny API surface, can learn in an afternoon), Relay will be way too much. I wouldn't bother reading more about them.

FB employs one of the world's best C++ developers (Andrei Alexandrescu) to write custom string implementations and maintain/extend their homegrown PHP VM. Their development practices would be completely unsustainable for any company that has anything resembling economic accountability.
Andrei left Facebook almost two years ago https://forum.dlang.org/post/xsqrdgwnzehdmfmvcznn@forum.dlan...
Ah, many companies have homegrown languages they use internally. You don't even have to be a big company to do so. Wasabi is an example of that.
True; I just disagree with the general tendency to treat everything FB or Google does as the holy grail of best practices (or even good at all) for the average company.