07:39 | <ljharb> | they're working on a new config system, and it supports ESM, and thus it has to be async |
07:39 | <ljharb> | so i don't see why they'd be opposed to rules working that way |
07:43 | <bakkot> | https://github.com/eslint/eslint/issues/15394#issuecomment-989410995 |
07:43 | <bakkot> | ¯\_(ツ)_/¯ |
07:44 | <ljharb> | i read your gensync thing and i still really don't understand the point. if you already have both a sync and async version, then sure, and if you only have a sync version, then it's pretty trivial to wrap that in an async function, but if you only have an async version then how can you make it sync? |
07:45 | <bakkot> | the idea is that sometimes your thing is async only because it needs to call a user-provided function, which may or may not be async |
07:45 | <bakkot> | if the user-provided function is async, you of course need to be async |
07:45 | <bakkot> | if it is not, it is nice not to be |
07:46 | <bakkot> | (the post has a concrete example of when that might come up) |
07:48 | <ljharb> | but like, if the user's providing a "read file" method, why wouldn't you just return whatever it returns? |
07:48 | <ljharb> | like if it returns a promise, you return one, if not, not |
07:50 | <bakkot> | because you need to do stuff with the thing inside the promise |
07:50 | <ljharb> | i guess i'm just really not getting why this is an issue outside of what seems like a very rare use case - where a user is providing a maybe-sync maybe-async method, but you need to do processing on each result, and you can't call the function for the next result until you do that processing |
07:50 | <ljharb> | or why you couldn't have two interfaces - a sync one and an async one - that both share an internal processing function |
07:51 | <bakkot> | yes, you could split up all your code so that it is in continuation-passing style, and then invoke the callbacks synchronously when the result of the user-provided function is available synchronously, but the point of async-await is that writing CPS by hand sucks |
07:52 | <bakkot> | I invite you to go through the exercise of refactoring the getTransitiveDependencies function so that it works that way; it is not a trivial refactor |
07:54 | <bakkot> | this problem comes up basically any time you're writing a utility which takes a function as an argument and does something with the return value of that function; this is not rare, in my experience, though it may be in yours |
07:55 | <ljharb> | certainly that's not rare in my experience, i do that all the time, but i've never had this problem come up before that i can recall |
07:55 | <ljharb> | but to be fair i almost never use async/await (altho i often work with promises) |
07:56 | <ljharb> | i also often write eslint code that works sync with dependencies - like the ExportsMap in eslint-plugin-import - but it doesn't accept a user-provided file reading mechanism, it just hardcodes it |
07:58 | <bakkot> | yeah, if you hardcode all your IO the issue comes up less; I generally try pretty hard to keep the IO at the boundaries, so that the core logic doesn't do any IO itself |
07:58 | <bakkot> | except by invoking user-provided stuff |
08:00 | <bakkot> | it does still come up, though; the last time I ran into this problem was when I wanted to offload some expensive computation to a worker, which meant the result of the computation was suddenly async, and I had to go rewrite everything to add async in a bunch of places and the library was no longer usable in sync contexts |
08:01 | <ljharb> | why do you need async everywhere versus return isPromise(p) ? p.then(f) : f(p) or something? |
08:01 | <bakkot> | because the function call is in the middle of a bunch of other logic |
08:03 | <bakkot> |
|
08:03 | <bakkot> | it is definitely possible to refactor this so that it just uses .then instead of await , but it's extremely annoying |