It also means that you can start up asynchronous stuff all at once, and then do things with the futures/promises before they resolve, instead of having to work around it blocking by default
The main thing I dislike is a distinction between async and normal functions. That should the interpreter's/compiler's job and it makes async-ifying synchronous code a nightmare
async should honestly be the default and where strict sequential evaluation is needed that should be provided for by a mix of explicit sequencing and compiler guesswork
(which is another argument for .await over await xyz(), since it's way easier to just paste that after the function call instead of having to check if the parenthetization is right and stuff)
I actually don't mind having to spam async/await, especially in Rust where verbosity around that sort of thing is kind of important, but I guess another option would be the compiler guessing where they're needed, and having a syntax to explicitly tell it to return a promise from a function call
E.g., xyz() would return the result, and await it if xyz is async (invisibly making the function the call is in async too if this occurs), and xyz?() would return the future unchanged if xyz is async, or wrap the result of xyz in a resolved future otherwise
That way you get select/join when you need them, but the far more common option of just awaiting is the default, and no distinction between async and non-async functions ever needs to be made
I actually might include this in Tundra, since it's intended to be written iteratively, and I've definitely run into "oh no, 20 new features in I need to add an async library" in JS before when doing that
Like rSNBATWPL. I had like a thousand sloc, thousands of function calls, then I realized I needed them all to be async since I'd doing I/O asynchronously. That was a lot of copying and pasting.
@RadvylfPrograms I feel like there's probably some big problem with this approach, which is why existing languages don't do it, but I don't understand async enough to guess what it is. So I'd say go ahead and do it this way in Tundra, and then if there's a big problem with it, you'll find out and we can all learn something. :D
Inspired by my realization of why I like JS so much, that being that I can kind of just jump in and start writing stuff, whereas Rust takes more planning and kind of bullies you into writing bug-free, finished code
LDQ: What are good names for the following two operations? They both take a list L and a number N. One operation splits L into sublists of length N; the other splits L into N sublists of equal length.
@DLosc In Pip, they are called Group (<>) and Chop (CH). I don't like how unrelated the two names are, tho. (Chop was added much much later than Group.)
@RadvylfPrograms yeah i feel like chop is too conceptually similar to chunk--if you're chopping vegetables, chances are you don't care how many slices you end up with, but you do care about he size
LDQ: Do you prefer Python's * or JS's ...? *'s quicker to type, but I feel ... is more intutiive and harder to confuse with things from other languages
conceptually i imagine for specifying varargs it looks like a kleene star (but on the wrong side of the expression :P) and for splatting into them it looks like something that has gone splat on your screen
but it's still the same character as the multiplication operator and c's dereference
Issue with .. is that I'm probably already using it for ranges, and it's got all sorts of meanings in different languages, none of which are splatting AFAIA
(still prolly going for + tho since both JS and Python use it)
@lyxal Oh well that's used by my brand new "first-class redaction" feature where you can redact parts of your code in order to more easily treat them as black boxes
@UnrelatedString actually that gives me an idea - what if varargs modifiers were postfix in function headers instead of prefix and you used ? for optional, * for 0 or more and + for one or more arguments