09:22 | <pokute> | I've been dogfooding my TypeScript support for pipeline operator at https://github.com/Pokute/AoC2021/blob/main/4.ts . It's starting to feel crucial for me. Lacking tacit function application (|>> ) would be an inconvenience, but the other way around, I would have so many IIAFEs. |
20:28 | <bakkot> | A proposal: https://gist.github.com/bakkot/3d0f81233fc00b508ae5f247b1458823 tl;dr: adding syntax for defining a function which can be either sync or async, depending on how it's called:
|
20:28 | <bakkot> | looking for any feedback on whether this seems at all reasonable before I put together something to present to committee |
20:46 | <Justin Ridgewell> |
|
20:48 | <bakkot> | I had not! |
20:49 | <bakkot> | but that is basically exactly the same thing, neat |
20:55 | <loganfsmyth> | Let me know if you have suggestions for improvements, I think babel is the only thing really using it right now. |
21:08 | <bakkot> | main thing which looks to be missing to me is a way for the function to switch on whether it was called as sync or async |
21:08 | <bakkot> | so that it can e.g. call the appropriate sync or async version of some other API |
21:09 | <bakkot> | (my gist has a function.async meta-property for this; it would be a bit harder to do in a library) |
21:14 | <loganfsmyth> | Got it, should be pretty easy for you to make a helper to do that since you can make a function where the async version returns true and the sync version returns false and then do if (yield* isAsync()) { |
22:28 | <nicolo-ribaudo> | Got it, should be pretty easy for you to make a helper to do that since you can make a function where the async version returns true and the sync version returns false and then do |
22:31 | <loganfsmyth> | Hah I though it did but I was on mobile and couldn't be bothered to look |
22:32 | <loganfsmyth> | Certainly something we could move into gensync too |
22:34 | <nicolo-ribaudo> | Btw, something that would greatly benefit from moving this to the language (rather than as a library) are stack traces and step-by-step debugging; gensync makes it really hard (this is not a critique, just a limitation I don't think can be solved in a library). |
22:53 | <bakkot> | I think the main annoying thing with the library version is that you can't call regular async functions without wrapping them first (unless I'm missing something) |
22:53 | <bakkot> | not a huge hinderance but would be nicer not to need to worry about it |
22:54 | <bakkot> | anyway, this is really cool; I will play with it some |
22:55 | <nicolo-ribaudo> | Well, it's await? (function.async ? asyncFn() : syncFn()) vs yield* gensync({ sync: syncFn, async: asyngFn })() (you need the check in both versions) |
22:55 | <nicolo-ribaudo> | But yes, you always need to wrap |
22:56 | <bakkot> | with the syntax you need to wrap if you're calling a function you figured out yourself, but not if you're calling a function the user provided |
22:57 | <bakkot> | i.e. you can just do await? callback() and if the user called you as f.async and passed an async callback, or if the user called you as f.sync and passed a sync callback, it will work the same |
22:57 | <bakkot> | and callback doesn't need to be wrapped |
22:58 | <nicolo-ribaudo> | Oh ok yes, we had to introduce a maybeAsync gensync helper in Babel for that |
22:58 | <nicolo-ribaudo> | (which also throws if callback() returns a promise when called in a sync context) |
22:59 | <bakkot> | yeah there's definitely some possibility of shooting yourself in the foot here, if you mess up what's async and what's sync |
23:00 | <bakkot> | this would be fun for typescript to figure out :P |