4 ms·
One point I massively miss from this discussion is retrofitting. Imagine the following situation: I have a webserver which calls a parser module which calls an
by Sebb767 6y ago
One point I massively miss from this discussion is retrofitting. Imagine the following situation: I have a webserver which calls a parser module which calls an external library which calls a closure in my code during parsing. Now this call needs to write to a log, which is async due to a file write or so.
To implement this I need to touch the webserver core, implement a breaking change in the parser library and get a new external library, just to get my log line in this function. This is a massive refactoring effort just to get a line in my log. It's purer and better style, yes. But now I need a few days for what should take five minutes.
If the codebase is designed from the ground-up with async in mind (which probably means to make basically every non-leaf async, to avoid the situation above), this is fine. If I'm working with an existing codebase, this does not work. I see why people don't want a fallback - it leads to bad code in cover. But allowing this and simply marking it via linter would make step-wise upgrading so much easier and alleviate 90% of the problems.
EDIT: My concerns are specific about JavaScript/TypeScript. I think Rust got this right.
- BenoitP 6y agoOne of the best retrofitting effort there is is Java's Loom IMHO. Instead of trying to solve the IO bottleneck on a few threads with async, it just reduces the Thread footprint and allows you to have millions of them. Good'ol Tomcat is going to massively improve its IO concurrency overnight with just a simple `Thread.builder().virtual().factory()`.
- zozbot234 6y ago> To implement this I need to touch the webserver core, implement a breaking change in the parser library and get a new external library, just to get my log line in this function. This is a massive refactoring effort just to get a line in my log. Not quite. It's very easy in Rust to purposefully block on an async call in sync-only code, or spawn blocking code on a side thread in async code and let it "join" whenever the async code block gets executed. Of course you'll get less-than-optimal performance, but no program-wide refactoring is required.
- Sebb767 6y agoSorry, I was talking specifically about TypeScript/JavaScript. I edited the original comment to reflect this :)
- valenterry 6y ago> Now this call needs to write to a log, which is async due to a file write or so. Well, think about, without having a specific language in mind. There are multiple ways you want everything to be executed: 1. The library should call your function and wait until both parsing and writing to the file is finished before executing any other action 2. The library should call your function and wait until both parsing and writing to the file is finished, but potentially execute other actions (e.g. other parsing for another request) in the meantime / in between. 3. The library should call your function and wait until parsing is finished but not wait until writing to the file is finished (which also means to disregard the filewrite result) The only way to really control how things happen is to have the library be aware of potential concurrency and that is true for Rust as well. There is no other solution, except for "hacks" which, when used, will make it impossible to understand what a piece of code does, without reading _all_ the code. Similar to global mutable variables (because that is what it would be). If you application is small or not so critical, then you might indeed get away with a hack, but I think the energy should be focussed on improving languages so that libraries can easily be rewritten to embrace concurrency, rather than allowing for more hacks.
- ItsMonkk 6y ago> webserver which calls a parser module which calls an external library There's your problem right there. Nested calls are killing us. That parser module should be a pure transformation function. If it has requirements, your main webserver should be fetching it. If you need to first query the parser to know if it has any requirements for this call, you can do so as a separate pure function. That query will then respond with a value that your webserver can then use to call the external library with. When the impure external library responds, with no external changes, you can now pass that into the parser module to get your parsed object out. Now when you want to add logging to the external library, ideally you can do so at the webserver level, but otherwise you only need to add logging to the external library, and your parser doesn't change at all.