I recently started working with Rust async. The main issue I am currently facing is code duplication: I have to duplicate every function that I want to support both asynchronous and blocking APIs. This could be great to have a `maybe-async`. I took a look at the available crates to work around this (maybe-async, bisync), but they all have issues or hard limitations.
There is work happening on keyword generics[0], which would let a function be generic over keywords like `async` and `const`.
For now the best option to write code that wants to live in both worlds is sans-io. Thomas Eizinger at Fireguard has written a good article about this[1] pattern. Not only does it nicely solve the sync/async issue, but it also makes testing easier and opens the door to techniques like DST[2]
I have my own writing on the topic[3], which highlights that the problem is wider than just async vs sync due to different executors.
Yes I hope in the future we can get to what OCaml 5 has with their algebraic effects system, and hopefully fix any flaws we see in there, so that async will just be syntactic sugar over the underlying effects system.
I may have missed something, but how does “sans-io” deal with CPU heavy code? For example, if there’s some heavy decoding/encoding required on the data? Does the event loop only drive the network side and the heavy part is done after the loop is finished?
This is a great question and there isn't a definitive answer provided in the sources I linked.
Broadly I think there are three approaches:
1. For frequent and small CPU heavy tasks, just run them on the IO threads. As long as you don't leave too long between `.await` points (~10ms) it seems to work okay.
2. Run your sans-io code on a dedicated CPU thread and do IO from an async runtime. This introduces overhead that needs to be weighed against the amount of CPU work.
3. Have the sans-io code output something like `Output::DoHeavyCompute { .. }` and later feed the result back as `Input::HeavyComputeResult { .. }`, in the middle run the work on a thread pool.
> For now the best option to write code that wants to live in both worlds is sans-io
Thanks for sharing!
Reading the articles, it looks at me, it is a kind of manual reimplementation of the state machine generated by async? This also makes the code harder to reason with. I am unsure if it is worth the complexity.
One of the issue I face is a blocking function that takes a generic constrained by a `trait` and its async version takes a generic constrained by an `async trait`.
In my perspective, an "async" function is already an "maybe-async". The distinction between a a `fn -> void` and `fn -> Future<void>` is that the former executes till its end immediately, whereas the other may only finish at another time. If you want to run an async fn in a blocking manner, you would use a blocking executor.
There is a relevant Wikipedia page about minifloats [0]
> The smallest possible float size that follows all IEEE principles, including normalized numbers, subnormal numbers, signed zero, signed infinity, and multiple NaN values, is a 4-bit float with 1-bit sign, 2-bit exponent, and 1-bit mantissa.
Note that `--no-remote` breaks starting new browser windows from outside, which users normally want.
I'm starting to think that setting the `HOME` environment variable is the only way to really make things isolated - this still won't handle `~insertusernamehere` but basically everything else respects it.
On windows powershell I do
Start-Process "C:\Program Files\Mozilla Firefox\firefox.exe" -ArgumentList "-P default-release"
Which is the exact same idea.
Yes, I tried that and everything else. Either it refuses to launch with `--new-instance` or (from memory, in the case of your command) subsequent `--new-tab`s may open in the wrong profile. Presumably due to the order in which the original instances were created. The point is that the system turns on these UIDs, which are not paths or even hashes of paths.
I tried Helix two years ago, unfortunately the default keymap was a bit frustrating to me. I don't mind changing my habits, however I had difficulty I made sense of the keymap design.
For example, typing `w` select the word. However, typing `2w` select the second word and not two words. To select two words you have to enter in visual mode (`v2w`). To remove two words you thus need to type `v2wd` or `wdwd`. In Vim you can type `d2w`. I miss this composability.
In Kakoune (one of the main inspiration of Helix), you can type `2Wd` (`2wd` has the same behavior as Helix).
I was also hoping that the use of Ctrl/Alt modifiers be completely removed. Why not fully embrace modal editing?
If I remember correctly, TCO is now part of the ECMAScript standard. Safari has implemented it. The issue is that others engines have not because they are concerned about stack unwinding and stacktraces.
I was quite excited by the description and then I noted that Bolt heavily relies on double floating point numbers. I am quite disappointed because this doesn't allow me to use Bolt in my context: embedded systems where floating point numbers are rarely supported... So I realized that I misinterpreted `embedded`.
Wouldn't that be a mess to parse? How would you know that "He said " is not a string literal and that you have to continue parsing it as a multiline string? How would you distinguish an unclosed string literal from a multiline string?
reply