HNHacker News
TopNewBestAskShowJobs

withoutboats3

1,099 karma · joined March 8, 2023

submissionscomments
withoutboats3··on Async Rust is not safe with io_uring
I don't consider Yosh Wuyts's concept of "halt safety" coherent, meaningful or worth engaging with. It's true that linear types would enable the encoding of additional liveness guarantees that Rust's type system as it exists cannot encode, but this doesn't have anything to do with broken io-uring libraries leaking resources.
withoutboats3··on Async Rust is not safe with io_uring
This is nothing to do with async Rust; monoio (and possibly other io-uring libraries) are just exposing a flawed API. My ringbahn library written in 2019 correctly handled this case by having a dropped accept future register a cancellation callback to be executed when the accept completes.

https://github.com/ringbahn/ringbahn

withoutboats3··on Rewriting Rust
My blog is located at https://without.boats

Here are some relevant posts:

https://without.boats/blog/a-four-year-plan/

https://without.boats/blog/poll-next/

https://without.boats/blog/asynchronous-clean-up/

https://without.boats/blog/pinned-places/

withoutboats3··on Rewriting Rust
I did work at Mozilla; I stopped contributing to Rust after Mozilla stopped funding the project.
withoutboats3··on Rewriting Rust
I agree with that assessment of Pin. That's why the second post I linked to presents a set of features that would make it as easy to use as mutability (pinning is really the dual of immutability: an immutable place cannot be assigned into, whereas a pinned place cannot be moved out of).
withoutboats3··on Rewriting Rust
I don't deny that Pin is complicated to use as it stands (in fact that is the entire thrust of my blog posts!), just that there is some magical easier solution involving Move and changes to the borrow checker. You wrote something on the back of a napkin and you imagine its better, whereas I actually had to ship a feature that works.

The state of async Rust is not better because no one hired me to finish it past the MVP. I have solutions to all of your problems (implementing a stream with async/await, making Pin easier to use, etc). Since I am not working on it the project has spun its wheels on goofy ideas and gotten almost no work done in this space for years. I agree this is a bad situation. I've devoted a lot of my free time in the past year to explaining what I think the project should do, and its slowly starting to move in that direction.

My understanding is that if let chaining is stalled because some within the project want to pretend there's a solution where a pattern matching operator could actually be a boolean expression. I agree that stalling things forever on the idea that there will magically be a perfect solution that has every desirable property in the future is a bad pattern of behavior that the Rust project exhibits. Tony Hoare had this insightful thing to say:

> One way is to make it so simple that there are obviously no deficiencies and the other way is to make it so complicated that there are no obvious deficiencies.

> The first method is far more difficult. It demands the same skill, devotion, insight, and even inspiration as the discovery of the simple physical laws which underlie the complex phenomena of nature. It also requires a willingness to accept objectives which are limited by physical, logical, and technological constraints, and to accept a compromise when conflicting objectives cannot be met. No committee will ever do this until it is too late.

withoutboats3··on Rewriting Rust
If you actually read my posts you would see that I acknowledge and analyze the difficulty with using Pin and propose a solution which makes it much easier to deal with. My understanding is that the Rust project is now pursuing a solution along the lines of what I suggested in these posts.
withoutboats3··on Rewriting Rust
These features are slow to be accepted for good reasons, not just out of some sort of pique. For example, the design space around combining `if let` pattern matching with boolean expressions has a lot of fraught issues around the scoping of the bindings declared in the pattern. This becomes especially complex when you consider the `||` operator. The obvious examples you want to use work fine, but the feature needs to be designed in such a way that the language remains internally consistent and works in all edge cases.

> Pin didn't take much work to implement in the standard library. But its not a "lean" feature. It takes a massive cognitive burden to use - to say nothing of how complex code that uses it becomes. I'd rather clean, simple, easy to read rust code and a complex borrow checker than a simple compiler and a horrible language.

Your commentary on Pin in this post is even more sophomoric than the rest of it and mostly either wrong or off the point. I find this quite frustrating, especially since I wrote detailed posts explaining Pin and its development just a few months ago.

https://without.boats/blog/pin/ https://without.boats/blog/pinned-places/

withoutboats3··on QUIC is not quick enough over fast internet
Rust's async model can support io-uring fine, it just has to be a different API based on ownership instead of references. (That's the conclusion of my posts you link to.)
withoutboats3··on Fear Not the Association of Types
Yes, this is the actual reason. In Java you're restricted to one implementation of an interface for a type by syntactic construction (classes list their interfaces in their header and each interface can only appear once). In Rust there is a similar restriction (called coherence), but it takes into account all of the parameters to a trait, including its generics.

An illustrative example of the difference: `AsRef<T>` and `Deref` have almost identical signatures, except that the target type for `AsRef` is a parameter and for `Deref` is an associated type. `String` implements `AsRef<str>`, `AsRef<Path>`, and so on, but only `Deref<Target = str>`.

The blog post's meandering description the difference between static and dynamic dispatch has no relevance whatsoever.

withoutboats3··on Pin
This comment contains a link to a detailed technical explanation of why the person I was replying to was wrong. Does your browser not support websites others than Hacker News? What is this peculiar delusion you have in which content not written into this little box is not real content?

Hacker News comments are divided between useful, inquisitive engagement, to which I react positively and smarmy, self-important bullshit, to which I react with scorn. You have made clear your allegiance to the latter. Sad!

withoutboats3··on Pin
I created new accounts because I didn't register with an email and lost the login. What a nasty person you are! Why don't you go create something?
withoutboats3··on Pin
I didn't ask for this to be posted on Hacker News, genius. My engagement with this community is a generous use of my free time, but I do not suffer trolls and cranks like simon-o.
withoutboats3··on Pin
This is literally a thread about a post on my blog. If you can’t find my body of work, I cannot help you.
withoutboats3··on Pin
I agree that this definition of Unpin should be improved, but I'm confused about the scenario you're describing. When does a user encounter an error because of Unpin?

Is it just that they use an API which requires Unpin? If so, what APIs do you encounter causing the issue most often?

withoutboats3··on Pin
The behavior and performance of asynchronous function depend on the behavior and performance of concurrent processes, making them more complex to reason about, test and be confident in their correctness and well-suitedness.
withoutboats3··on Pin
In my next post, one of the major features I write about is pinned projection, and its true: for any type that supports pinned projection, it needs to decide for each field if pinning is transitive or not. This is different from how mutability works (mutability is always transitive).

There is a more elegant design which is basically reversed from pinning, but that's backward compatible with Rust. I also describe that in the next post. This pinned fields vs unpinned fields aspect of the behavior is the "necessary accidental complexity" of existing in the context of all in which we live and what came before us.

withoutboats3··on Pin
I've written thousands of words on my blog about the design of async Rust, in which I carefully explain every decision and discuss the strong and weak points. This person regularly post rude low-effort comments like this one. My body of work should be enough to refute the idea that all I'm doing is doubling down.
withoutboats3··on Pin
[flagged]
withoutboats3··on Pin
Marking the difference between a function that synchronizes with a concurrent process and a function that does not is good, actually.
withoutboats3··on Pin
Thanks for your write up. This sounds like a perfect use case for async generators (which yield many times and compile to Stream instead of Future), a feature I hope Rust will gain in the next year or two. To receive messages from other parts of the program, I would have the async generator hold the receiving end of a channel.
withoutboats3··on Pin
I'm curious why you needed to deal with `Pin` instead of using async functions. What led you to a path in which you needed to implement poll methods yourself?

For what it's worth, all of the practical problems you encountered with using Pin are exactly what my next post is to show how to solve.

withoutboats3··on Pin
Could you link to a source for this in Mojo's documentation? This would be a logical interpretation, but it would mean Mojo is planning to adopt a much worse implementation of async than Rust and the post is claiming that Mojo is both faster and easier than Rust.
withoutboats3··on Pin
There are a couple of ways to interpret this code:

1. If this were public, or if you ever move out of the reference you get from that function, you would be violating the pin contract so this code would then be invalid.

2. Since its impossible to depend on the pin contract generically and this type doesn't actually depend on it, this is really just an indirect equivalent of implementing Unpin for the type, which is safe, so this code is valid.

I do think the second interpretation is correct (and I think its what the UCG group has decided), but this is a really nuanced conversation about the interpretation of unsafe code and validity. You started this thread by saying this is the reason pin is difficult for users: I am completely certain the median user is not in the weeds about what is and isn't valid unsafe code in pointless hypotheticals; the totally different set of idioms to get the same behavior for pinned references as for ordinary references is a much more pressing issue.

withoutboats3··on Pin
I think this is good feedback and it would be good for the docs to be clearer about this. Of course for the types that you're going to deal with pinned (futures and streams), they're a lot more likely to be those niche objects.

I also do think the documentation has improved a lot over the years. I was surprised when I checked it while drafting this that it seemed to focus on the right things pretty well; circa 2019 I remember it being a lot more focused on specifying the contract in a way that really belongs in something like the Rust reference and not the std API docs.

withoutboats3··on Pin
It's clear that Mojo is in some sense inheriting Swift's notion of "value semantics," but Rust also has "value semantics" in the same sense. Rust just also has references as first class types, whereas Swift (and as far as I can tell, Mojo) only allows references as a parameter passing mode; Mojo expands on Swift's inout parameters by having an immutable reference passing mode as well.

Not being able to store references in objects does solve the problem of "self-referential structs" in that you just can't implement code like the code Rust compiles to, but that isn't at all what the quoted paragraph says about Mojo so I am quite lost as to what they mean.

withoutboats3··on Pin
Pin does have meaning: it means you cannot move the target of this pointer ever again (or invalidate its without running its destructor, which is what moving does that's the problem), unless the type of the target implements Unpin.

This giving up of certain rights gives other rights (such as to store self-referential values), which are the reason you give it up. This is how contracts between components just work: similarly, giving up the right to mutate through a reference allows you to alias the reference at the same time. I'm always reminded of this line from Lincoln, about a very different and much graver subject: "If we submit to law, Alex, even submit to losing freedoms - the freedom to oppress for instance - we may discover other freedoms previously unknown to us."

I do agree that the fact that you can't use those rights in safe code is an educational problem, because one can't easily demonstrate what you can do with a pinned reference except "call a poll method which the compiler has generated for you."

withoutboats3··on Pin
This is true. When were working on the problem, the way Aaron Turon put it was that &mut is "too powerful." If &mut didn't give the power to move out of it, the whole design would be a lot simpler. I'll discuss this in my next post about this.

Rust has to be backward compatible and already decided you can move out of an &mut, but there are definitely cleaner designs that can be, unburdened by what has been.

withoutboats3··on Pin
You don't need move constructors if every future is heap allocated. But then every call to an async function is a separate allocation, which is terrible for memory locality. Some kind of virtual stack would be much better than that (but then you need garbage collection if you want the stacks to be memory-optimized to be small by default).
withoutboats3··on Pin
This isn't why development is slow. In my opinion, if I were still employed to work on Rust improvements to async would have shipped a lot faster. My blogging about it in my free time is my effort, in light of my circumstances, to get the project back to shipping on async.
← PreviousPage 2 of 5Next →