Live data from Hacker News

Building a shared vision for Async Rust

blog.rust-lang.org

121–130 of 139 posts

Re: Building a shared vision for Async Rust

#121
post #112

Earlier quoted context omitted.

Rust has lots of nonsense with zero practical benefit. Examples: PhantomData, higher-ranked trait bounds, "upstream crates may add a new impl". I have satisfied the compiler but no bugs were prevented. It's just busywork.

You don't have to use PhantomData. > "upstream crates may add a new impl" I have satisfied the compiler but no bugs were prevented. Trial-and-error debugging which version causes a bug is busywork, preventing it right when someone introduces the potential problem is at best annoying, but very fast compared to the alternative.

You do have to use PhantomData, otherwise it won't compile:

https://play.rust-lang.org/?gist=84883cb7cdd09acdcd919888cef...

It's especially bad if your type is an enum, since there's no obvious place to put the PhantomData:

https://github.com/rust-lang/rust/issues/32739

> Trial-and-error debugging which version causes a bug is busywork, preventing it right when someone introduces the potential problem is at best annoying

It's a silly limitation. For example, u64 and u128 are not From because...well I have no idea. But you can't make them From, because Rust wants to reserve the right to make them From in the future. And you can't write a function that assumes they are NOT From, for the same reason.

So it's pointlessly hard to write generics over integers. I encounter lots of weird holes like this.

https://play.rust-lang.org/?gist=600a1ca784ee7df02351e58df43...

Re: Building a shared vision for Async Rust

#122
post #68

Earlier quoted context omitted.

> C# ties you to CLR C++ and Rust have runtimes as well. For C++ that’s normally a DLL like libstdc++ or msvcrt. CLR is larger but still reasonable, for 64-bit Windows VC_redist.x64.exe is 14 MB, dotnet-runtime-3.1.13-win-x64.exe is 25 MB. > and is also garbage collected by default By default yes, but that’s avoidable. Modern .NET with their spans, value tuples, ref structs, ArrayPool, etc., make it relatively easy t…

Relevant to the topic, annoyingly, you still can't cancel a task without a ton of garbage.

You can easily forget pending tasks. That’s a single line of code like this:

  task.ContinueWith( t => { }, TaskContinuationOptions.OnlyOnFaulted );
However, graceful cancellation is indeed hard. Doable in .NET but not easy, you gonna need to manually pass these cancellation tokens all the way down.

Do you have an example of a language/runtime/etc where the cancellation's easy? It's easy to kill processes from the outside, but even for threads it's borderline impossible without horrible side effects.

Re: Building a shared vision for Async Rust

#123
post #67
post #8

I admire the passion, but I’m not sure why I would want Rust at all, not just async. When I want memory safety, async-await, I/O performance, easy multithreading, I write C#. When I want performance of CPU bound code, or lots of integration with native libraries/APIs, I write C++. Sometimes I want both in the same software, compile C++ code into a DLL (or shared library on Linux), and consume it from C#. I don’t have…

95% of people who think they want Rust should just be using OCaml or similar, IMO. That said, Rust should mostly be as easy to write and debug as C# - if it's not, that's a problem to be fixed. And interop between two languages causes more subtle issues that you don't notice - your architecture ends up distorted, refactoring across the interop boundaries is painful. I used to work on mixed C++/Python projects and tho…

> if it's not, that's a problem to be fixed

I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason.

> interop between two languages causes more subtle issues that you don't notice

I have some experience with python. C interop does work, but the usability is not OK. The languages and runtimes are just too different, which caused non-trivial amount of boilerplate to integrate the two. C# / C++ integration is much easier.

I remember a few times when I wanted to move that interop boundary, usually in the direction of “less C++”, but did nothing about that because development overhead was too large. And I agree that’s harmful in the long run.

Here’s a famous quote: https://en.wikipedia.org/wiki/Greenspun%27s_tenth_rule The idea does apply to all sufficiently complicated programs ever since: MS Office has VBA, game engines have their scripting languages, AutoCAD has LISP, and so on.

I’m pretty sure that if in the future some programming language gonna become good enough to rule them all, that language will be much closer to modern C# than to modern Rust. Rust offloads a huge amount of complexity to developers (being such a developer, I don’t like that) and to the compiler (results in slow builds).

Re: Building a shared vision for Async Rust

#124
post #67

Earlier quoted context omitted.

95% of people who think they want Rust should just be using OCaml or similar, IMO. That said, Rust should mostly be as easy to write and debug as C# - if it's not, that's a problem to be fixed. And interop between two languages causes more subtle issues that you don't notice - your architecture ends up distorted, refactoring across the interop boundaries is painful. I used to work on mixed C++/Python projects and tho…

> if it's not, that's a problem to be fixed I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason. > interop between two languages causes more subtle issues that you don't notice I have some experience with python. C interop does work, but the usability is not OK. The languages and runtimes are just too different, which caused non-trivial amount of boilerplate to int…

> I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason.

Well sure, and in reality IDE support is a big reason I'm using Scala rather than Haskell. But the fact is that there are maybe 2.5 good IDEs going, and that seems like as much as the programming industry can support. So either we accept that the only way to make your programming language experience any good is to get it picked up by one of the handful of giant companies that can fund those IDEs, or we have to be willing to at least start a promising language without an IDE and hope other advantages can make up for that shortcoming for some use cases, and eventually there'll be enough momentum that one of those giant companies will pick it up. I can't see what other way there is to advance the state of the art, unless your position is going to be that C# is perfect and there's no point trying to do better.

> I’m pretty sure that if in the future some programming language gonna become good enough to rule them all, that language will be much closer to modern C# than to modern Rust. Rust offloads a huge amount of complexity to developers

What complexity is that? I'd argue that the trait system is a noticeable improvement over what's available in C#, and not having exceptions makes code significantly easier to understand. On linearity I could go either way - in theory it's more work for the developer, but borrow-checker friendly code styles tend to just be good coding style. Most of the time I write the same code I'd write in C#, Scala, or anything else, and it just work - and when it doesn't either the error messages have been clear and the fix has been easy, or it became clear that I was genuinely very confused about the problem and needed to rethink my whole approach.

(But yeah actually GC is fine 100% of the time and Scala is already the one language to rule them all, people just haven't realised yet)

Re: Building a shared vision for Async Rust

#125
post #68

Earlier quoted context omitted.

Relevant to the topic, annoyingly, you still can't cancel a task without a ton of garbage.

You can easily forget pending tasks. That’s a single line of code like this: task.ContinueWith( t => { }, TaskContinuationOptions.OnlyOnFaulted ); However, graceful cancellation is indeed hard. Doable in .NET but not easy, you gonna need to manually pass these cancellation tokens all the way down. Do you have an example of a language/runtime/etc where the cancellation's easy? It's easy to kill processes from the outs…

I don't. I don't use Rust but I'm quite sad I can't use this system in C# without paying for a stacktrace/exception. Cancellation tokens sure...but many libraries will still throw the cancellation exception.

Re: Building a shared vision for Async Rust

#126
post #124

Earlier quoted context omitted.

> if it's not, that's a problem to be fixed I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason. > interop between two languages causes more subtle issues that you don't notice I have some experience with python. C interop does work, but the usability is not OK. The languages and runtimes are just too different, which caused non-trivial amount of boilerplate to int…

> I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason. Well sure, and in reality IDE support is a big reason I'm using Scala rather than Haskell. But the fact is that there are maybe 2.5 good IDEs going, and that seems like as much as the programming industry can support. So either we accept that the only way to make your programming language experience any good is…

> What complexity is that?

First and foremost ownership shenanigans. The complexity spill over the entire ecosystem. You can't write a fizz buzz without discovering the standard library has 2 types of strings because of that.

> not having exceptions makes code significantly easier to understand

Both error codes and exceptions have their place. Imagine a streaming parser of some XML/JSON/mpeg4/whatever. There's nothing you can possibly do in the parser to handle socket errors. Exceptions make parser's code more readable, essentially you pretend sockets never fail.

> confused about the problem and needed to rethink my whole approach

No amount of rethinking gonna help when you need a graph data structure in your code. Ownership shenanigans making graphs complicated in Rust, fundamentally so.

Re: Building a shared vision for Async Rust

#127
post #112

Earlier quoted context omitted.

You don't have to use PhantomData. > "upstream crates may add a new impl" I have satisfied the compiler but no bugs were prevented. Trial-and-error debugging which version causes a bug is busywork, preventing it right when someone introduces the potential problem is at best annoying, but very fast compared to the alternative.

You do have to use PhantomData, otherwise it won't compile: https://play.rust-lang.org/?gist=84883cb7cdd09acdcd919888cef... It's especially bad if your type is an enum, since there's no obvious place to put the PhantomData: https://github.com/rust-lang/rust/issues/32739 > Trial-and-error debugging which version causes a bug is busywork, preventing it right when someone introduces the potential problem is at best anno…

I meant that you are not forced to use generics, you can use composition, boxing, dyn, etc. (And unsafe too, but PhantomData seems simpler.)

> For example, u64 and u128 are not From because...well I have no idea.

Because usize is not known statically, it's target arch dependent. Yes, it's silly, but that's how technical safety works. (Also, just as a silly technical counter example the AS/400 virtual instruction set has 128 bit sized pointers.)

There's no question about the need for more ergonomics. That's what this whole post is about after all. For example in some cases where currently PhantomData is needed the intent of the programmer can be easily and unambiguously figured out, but for this folks need to be at least sufficiently certain that this makes things easier, makes code readable, doesn't constraint later language evolution, etc. (If I understand correctly some associated trait bound enhancements will lead to more readable code, less PhantomData.)

Re: Building a shared vision for Async Rust

#128
post #124

Earlier quoted context omitted.

> I agree, but it’s very expensive to fix. Visual Studio is a de-facto standard in many areas for a reason. Well sure, and in reality IDE support is a big reason I'm using Scala rather than Haskell. But the fact is that there are maybe 2.5 good IDEs going, and that seems like as much as the programming industry can support. So either we accept that the only way to make your programming language experience any good is…

> What complexity is that? First and foremost ownership shenanigans. The complexity spill over the entire ecosystem. You can't write a fizz buzz without discovering the standard library has 2 types of strings because of that. > not having exceptions makes code significantly easier to understand Both error codes and exceptions have their place. Imagine a streaming parser of some XML/JSON/mpeg4/whatever. There's nothin…

> Imagine a streaming parser of some XML/JSON/mpeg4/whatever. There's nothing you can possibly do in the parser to handle socket errors. Exceptions make parser's code more readable, essentially you pretend sockets never fail.

Disagree, because even if you can't handle errors in your code you have to do things like make sure resources are closed correctly. So you end up having to reason about exception safety, which is notoriously error-prone. If you have to have paths for propagating errors through your code, it's better to have them visible where you can reason about them, even if the actual handling has to take place at a different level.

> No amount of rethinking gonna help when you need a graph data structure in your code.

If you need a graph with cycles and you don't have a clear owner for the graph as a whole, sure. That's a pretty rare situation IME.

Re: Building a shared vision for Async Rust

#129
post #25
post #7

Is there any thought to including a default executor in the standard library? I think it's kind of an obstacle for beginners when the language/stdlib provide all the tools to write async code, but not to run it. I saw discussed in this talk the intent in allowing developers to provide their own executor based on the specifics of their use case: https://youtu.be/NNwK5ZPAJCk?t=1107 This makes sense to me; however, I fe…

> Is there any thought to including a default executor in the standard library? This is more difficult than you think, and you probably don't want the current async stuff to anchor to a weak implementation. For example, at least one of the current Rust async things doesn't work when pointed to UNIX/Linux character device file descriptors.

Are you talking about mio? If so, that might be the bug I've been trying to find all week.

Re: Building a shared vision for Async Rust

#130
post #128

Earlier quoted context omitted.

> What complexity is that? First and foremost ownership shenanigans. The complexity spill over the entire ecosystem. You can't write a fizz buzz without discovering the standard library has 2 types of strings because of that. > not having exceptions makes code significantly easier to understand Both error codes and exceptions have their place. Imagine a streaming parser of some XML/JSON/mpeg4/whatever. There's nothin…

> Imagine a streaming parser of some XML/JSON/mpeg4/whatever. There's nothing you can possibly do in the parser to handle socket errors. Exceptions make parser's code more readable, essentially you pretend sockets never fail. Disagree, because even if you can't handle errors in your code you have to do things like make sure resources are closed correctly. So you end up having to reason about exception safety, which i…

> you have to do things like make sure resources are closed correctly.

Not all code deals with resources. Streaming parsers normally don't. When you don't open/close any resources, manually propagating errors complicates code for no good reason.

> a graph with cycles and you don't have a clear owner

It's hard in Rust even for acyclic graphs with a clear owner, due to updates. Code that mutates the graph often needs to update multiple nodes at once, but Rust only supports a single writeable reference per object instance.

All practical Rust implementations of graphs, trees and linked lists I saw use unsafe to workaround the fundamental language limitation.

That's OK for linked lists because so simple and a standard library implementation is often enough. Graphs and trees however are very different based on use cases, can't implement just once and call it a day.

Post reply on HN