3 ms·
> And, it absolutely should not require creating two identical function definitions to get around the function coloring problem - that's completely indefensible
by CGamesPlay 2y ago
> And, it absolutely should not require creating two identical function definitions to get around the function coloring problem - that's completely indefensible.
I'm afraid I don't follow. It's impossible for you to have two identical functions (one sync and one async), since then they would both be sync. What did you mean?
- throw10920 2y agoTwo functions that are identical up to one of them being async and using "await" to call another function foo_async, and the other that is sync and calling foo_sync (a synchronous version of foo_async) without await?
- CGamesPlay 2y agoI think the only place that happens is in programming languages where you actually can choose to do something using a thread-blocking operation? Specifically, I've only seen it in Python. And yeah, it's not very ideal there. In other languages, it's typically only possible to do the operation in async mode, so you never write a foo_sync function in the first place.
- throw10920 2y agoThe "it's typically only possible to do the operation in async mode" is part of the problem. If I'm writing a a batch script that parses a file as part of its operation, I don't want or need the read_file() function to be async! My code should just block until the file opens. Alternately, I want to be able to designate a computationally-intense function call (just that call, leaving the other calls alone) as async so that control yields to the event loop. The main problem is that someone got it in their head that the function definition was the right place to designate whether a function was async or not, and it's not. The right place is the call site.
- spankalee 2y ago> The main problem is that someone got it in their head This unnecessarily trivializes the technical problems at hand. This wasn't just something someone got in their head, especially considering... > that the function definition was the right place to designate whether a function was async or not, and it's not. The right place is the call site. This is exactly what JavaScript did. The program only yields at `await`ed callsites and doesn't yield at all other callsites. `async` only tells the VM to create the state machine necessary to resume the function after `awaited` calls return.
- throw10920 2y ago> This unnecessarily trivializes the technical problems at hand. Making a language that automatically generates two versions of a function, one that is async and returns a Promise-wrapped object, and another that is sync, is not hard. > This is exactly what JavaScript did. No, it isn't. JavaScript requires you to declare functions as async at the function definition, and you can't call async functions from sync ones. This is exactly the thing I am arguing against, and is the opposite of "The right place is the call site."
- spankalee 2y agoIf it wasn't hard, it would have been done. I suppose we should all await your backwards compatible proposal? > No, it isn't. Yes, actually, it is. Async functions are a concept that only affects the internal structure of a function - to generate the state machine that allows yielding at `await` keywords and resuming after they resolve. Externally they are no different from "sync" Promise-returning functions. So they only thing that async functions do is enable yielding at the callsite, the `await` keyword is what actually yields at the callsite and you can await anything, not just async functions. Again: > I want to be able to designate a computationally-intense function call (just that call, leaving the other calls alone) as async so that control yields to the event loop. This is what `await` is - `await` yields. Non-await calls don't yield.
- 2y ago
- zogrodea 2y agoMy experience with this is in .NET, which has methods like readFile (which is async) and readFileSync. .NET doesn't really need to provide two separate utility methods like this though, because you can use Task.wait to block until the async task is done.
- neonsunset 2y agoFile.ReadAllBytes/Text/Lines use synchronous underlying file API. Their async variants call different OS APIs for asynchronous operation where available (Overlapped IO on Windows, on Linux it is specially scheduled (p)read and write calls). A similar distinction applies to Socket where asynchronous calls use an internal epoll-based engine while synchronous ones are plain send/recv. Generally speaking, in synchronous code there is no advantage to calling `.Wait()` or `.GetAwaiter().GetResult()` over synchronous APIs when such are offered, and if you can help it, it is best to update the code using them to be async too if your application is multi-threaded. Luckily it's quite easy in most situations unlike what HN public (that hates better languages like C#) would lead you to believe. But ff you do have to do block on waiting for a task, the impact on throughput is usually negligible if you do so within say threadpool worker - the implementation nowadays can cope with this very well and is more resilient to scenarios that used to be problematic.
- amluto 2y agoI sometimes wonder whether this is really an optimization problem pretending to be a coloring problem. In some sense, the sync versions of blocking things are generally better in only one way: they can be more performant (run faster, use less memory, generate shorter code, etc). [0]. If a function can be implemented in async/await style, then ISTM the compiler could treat the sync variant as an automatically generated optimization instead of as a totally different (and differently colored) variant. Of course, in languages like Rust with multiple colors of async code (single-threaded or multithreading-capable), this would get very messy. [0] As a major caveat, synchronous code also enforces various state transitions much more efficiently. Want to prove that IO is done (in the sense that the user code is done with it) before closing a file? This is pretty easy in single threaded blocking code.