question-mark
Stuck on an issue?

Lightrun Answers was designed to reduce the constant googling that comes with debugging 3rd party libraries. It collects links to all the places you might be looking at while hunting down a tough bug.

And, if you’re still stuck at the end, we’re happy to hop on a call to see how we can help out.

Proposal: metaprogramming with babel macros

See original GitHub issue

I think in the long term we’re going to have to do something about the amount of code duplication in iter-tools. The bulk of it stems from the fact that most of our implementations have almost identical copies for the async forms.

I do not think that we can or should want to try to consolidate the sync vs async methods to share code at runtime. I can expand more on my reasons for that, but perf is high among them, given the complexity that would be involved. We could however share code between implementations at compile time, and I think we should.

Babel macros are pretty cool, and a relatively recent feature of babel: they allow you to import a transformation into a source as a symbol. The macro is then passed the AST node that is called on, and given an option to inspect and transform it. Here’s what it might look like:

import a from "./macros/async";
a(function someMethod() {
  a(for(const item of iterable) {
    ...
  })
})

Which, when transpiled by babel, would be split into two outputs:

function someMethod() {
  for(const item of iterable) {
    ...
  }
}

and

async function someMethod() {
  for await (const item of iterable) {
    ...
  }
}

Fortunately in order to keep ourselves sane we already make sure that our sync and async implementations looks as similar to each other as we can make them. But this method of working gives us a lot of flexibility as well. For one it is opt-in not opt-out, so we can use it only where it really makes sense. It would even allow us to insert slightly different custom code into each method if we needed to:

import isAsync from "./macros/is-async";

if (isAsync) {
  // Only the contents of one block or the other would be present in output
  // ...
} else {
  // ...
}

Some more thoughts:

  • Babel macros are supported on astexplorer.net, making it relatively easy to test them out and figure out what the correct transformation code to apply is.
  • Because the macros have resolvable imports it will be far easier for new contributors to the project to discover the relevant transformation code and understand how the final code is generated.
  • Eventually (though it would not be necessary immediately) we could develop macros that would help us manage our tests for sync and async version of a function. This could help considerably. As low hanging fruit, the macros could easily allow us to generate real inputs which were sync for sync tests and async for async tests, instead of only testing the code paths where async methods are called on synchronous iterables. Consolidating the tests to the extent that they validate basic method behavior for both sync and async impls would also give us more energy to write tests for what may be genuinely different between the two versions.

Issue Analytics

  • State:closed
  • Created 4 years ago
  • Comments:8 (6 by maintainers)

github_iconTop GitHub Comments

1reaction
sithmelcommented, Apr 13, 2019

I can see we have some degree of repetition, but I am not sure it is worth to add such a complex element. I am afraid this will be raising the (already high) bar, for new contributors.

0reactions
conartist6commented, Jun 17, 2019

I am closing this as this technique is now deployed in the codebase. Work is outstanding still on the typescript types, but that will be tracked in #237.

Read more comments on GitHub >

github_iconTop Results From Across the Web

Feature request: support macros importing macros #48 - GitHub
I'm basically just experimenting with meta-programming in javascript ... Now babel-plugin-macros is able to import any local file as a macro ...
Read more >
Zero-config code transformation with babel-plugin-macros
A tool like this exists! babel-plugin-macros is a new Babel plugin that allows you to do exactly what we're talking about.
Read more >
Is there an equivalent of Julia's metaprogramming and macros ...
No, there is no equivalent. Neither ECMAScript nor TypeScript have macros. There is a proposal for Decorators, which would allow you to do...
Read more >
Clojure Macros and Metaprogramming - Hacker News
I've been programming in Clojure professionally for roughly ten years now. It's a great language and extremely effective if you're building ...
Read more >
I Can Babel Macros (and So Can You!) - Shawn "swyx" Wang
Babel isn't just for transpiling anymore! Shawn "swyx" Wang uses Moana to explain how Babel macros can help you with code generation and ......
Read more >

github_iconTop Related Medium Post

No results found

github_iconTop Related StackOverflow Question

No results found

github_iconTroubleshoot Live Code

Lightrun enables developers to add logs, metrics and snapshots to live code - no restarts or redeploys required.
Start Free

github_iconTop Related Reddit Thread

No results found

github_iconTop Related Hackernoon Post

No results found

github_iconTop Related Tweet

No results found

github_iconTop Related Dev.to Post

No results found

github_iconTop Related Hashnode Post

No results found