| 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 |