4 ms·
The criteria for this list of languages seems to have been "isn't JS". The story for metaprogramming in JS certainly is limited in some aspects; for example, th
by slikts 8y ago
The criteria for this list of languages seems to have been "isn't JS". The story for metaprogramming in JS certainly is limited in some aspects; for example, there's no operator overloading and JS isn't homoiconic like lisps, but between dynamic inheritance in older JS and the newer additions like proxies, symbols, accessors, reflection API, protocols and being able to extend the 'exotic' behavior of arrays, JS can probably still do whatever the snippet you posted is supposed to illustrate.
As a concrete example, here's a library I made that relies on symbols and dynamic inheritance to extend the built-in data types: https://github.com/slikts/symbol-land https://github.com/slikts/symbol-land
- wruza 8y agoI tried to include all my rant points into this example. E.g. what if fetch() doesn't go async? Then we don't have to mark it like that and don't have to await. Where ui and commit lives? There should be a unique environment for this specific api call or a whole subsystem. objs is something both enumerable and proxied, etc. It can be done in JS, but IRL it will be: ./file.js: function foo(ctx) { // @export for (let x of ctx.objs.iterate()) { x.a = await fetch(ctx, x.b); } ctx.ui.btnok.enabled = true; ctx.commit(); } autoexport(module, x => eval(x)); And more boilerplate, ceremony and fud down the way, if you go vanilla. (Thank you and all commenters here for sharing your code and experience. In particular, symbol-land looks very interesting and haskell-y.)
- slikts 8y agoHaving to explicitly mark where the control flow goes to the event loop with `await` is a very small price to pay for making the code much more clear. This is why I don't recommend node-fibers or deep coroutines in general. Destructuring would make your example look better: foo({ui, commit, objs}), and then there's no need for typing out ctx. Another thing that's not needed with for-of loops is .iterate(). Using eval() is a very strong anti-pattern, and it's not needed there anyway. JS has the `with` statement that allows running code with a specific context, but its use is discouraged as it's really bad for readability and hard to optimize.
- wruza 8y agoI used eval as a workaround; autoexport does fs.readFile() on module’s filename and adds all lines marked with @export comment to exports. Eval is the only way to get a function value from other module, since functions are local to the context that is implicit and only accessible through eval-ing closure. That’s my code and my company, so I don’t push it to anyone now or in the future. I know how important antipatterns are in general. Destructuring looks good here, you’re right. Actually, this thread somewhat relaxed my js hostility and I see it as an alternative that has reasonable tradeoffs (but still not as a friend though).
- slikts 8y agoI have trouble picturing what advantage that setup would give over using ESM or node modules. The Function constructor is a better alternative for eval(), but still only as a last resort. eval() itself has no use cases. I find that most JS criticism is ill-informed, because people are too quick to jump to blaming the language due to its reputation. Not that I'd call JS a great language, but it has redeeming aspects.