Live data from Hacker News

The Rust I wanted had no future

graydon2.dreamwidth.org

391–400 of 523 posts

Re: The Rust I wanted had no future

#391
post #331

Earlier quoted context omitted.

Then you are not the target audience of a low-level language that supposed to run without a runtime, but still safely. Don’t try to change the tool, when you could just choose a more fitting one.

Rust has an unsafe subset for that 0.001% of tne time you need it.

(Unsafe is a superset, not a subset, incidentally)

Re: The Rust I wanted had no future

#392
post #6

Very interesting insight from Graydon, in hindsight I too would have loved something more towards ML than C++. I never liked the kitchen sink approach that I see first C++, now Rust moving towards, but I respect what Rust has managed to solidify into. It's a good language. That said, I still hate async with a passion, it makes the language more complex and not very elegant (i.e. function coloring). And now that I kno…

If Rust was a higher-level language, then I'd say yes, just automatically handle running Futures in parallel, join them when you actually need to resolve the data, and pretend that they look like synchronous functions in the 80% of cases. Though things like `select!` wouldn't make any sense mixing the two.

I continue to find the "function coloring" argument misses the point unless you're arguing from a developer experience perspective. Why should two fundamentally different things look and function the same? Want this the ultimate pitfall of early RPC implementations where everything looks synchronous?

In Rust, a lot of the friction is due to how async functions/futures fundamentally differ in model of execution and how that interplays with the rest of the language. Other languages get to hand-wave a lot of these problems away with a GC. (It certainly could be less of a pain nonetheless.)

- Futures don't execute until polled, can partially execute if something isn't ready (and would block), can partially execute and be arbitrary cancelled and dropped. There is no equivalent in sync functions unless you make them co-routines.

- Since you can "pause" futures if something would block, you need a place to store the function's state for when it's resumed. Now you must be consider if the async function's state is `Send` if the future wants to move to a different thread to continue executing -- which is why you see `pin!` used. Sync functions don't care about this since you always run to completion on the same thread, and the stack is ephemeral.

- Likewise, the `Future` returned by the async function is going to need to encapsulate it's state that it saves. In the general case, this is a compiler generated anonymous struct that changes if any state saved across `.await` changes, hence the opaque `impl Future`. This is why you see `BoxedFuture` a lot to abstract this away at the expense of an allocation. Ideally, the new associated types with lifetimes can avoid this with traits.

So if all functions were co-routines (i.e. functions that can be resumed and re-entered) they would all have the same "color". But all you really did was "lift" all sync functions to be "async" functions with no internal await points.

(IMHO, if the C# team back in the day decided to implement full blown co-routines into the language instead of just `async/await` as a compiler trick, I think many other projects would have followed suit with a more general co-routine solution instead of treating `async/await` as this special thing which is just a specific compiler generated implementation of co-routines.)

Re: The Rust I wanted had no future

#393

Has Rust gone beyond the point of no return? Have less elegant features possibly been embedded in the language that have put Rust on the track to never become the hypothetically perfect or unblemished language?

The answer to your second question is "yes" for every single language that's ever been made or will be made.

Re: The Rust I wanted had no future

#394

Earlier quoted context omitted.

> Of course, a few of them of say they understand object lifetimes so well, they they don't need the static checker! There is a difference between understanding lifetimes and being able to keep track of them. I have a lot of objects in my more than 10 million lines of code. Most of them have simple lifetimes that are easy to track, but a few for reasons (which may or may not be valid - often the reasons are it was bu…

Being able to stop constantly keeping things in the back of your head and just trusting the compiler to complain if something is off was the biggest differentiator for me by far. Less footguns = more better

When I switch to C++11 and unitue_ptr things got a lot better. There is still a lot of cruft from old code, but C++ is a lot better as of 12 years ago. I don't let people manage raw pointers without good reason (I wouldn't let someone use unsafe rust without good reason either)

Re: The Rust I wanted had no future

#395

I love Rust and built some production code with it in the past. But nowadays I want something more simple so that not-so-senior developers can pick it up quickly, and I want flawless tooling, and willing to sacrifice a bit of performance. So basically I often end up with Go. Go is exceptionally great in tooling, ecosystem, any objective metrics like build times or crosscompilation... but I still don't like the langua…

Nim gets real close. It doesn't have great UI tooling, but its command line tools are quite good.

Yeah I've been looking into Nim and I want to build something substantial in it and see how it performs and feels to write.

Re: The Rust I wanted had no future

#396
post #6

Very interesting insight from Graydon, in hindsight I too would have loved something more towards ML than C++. I never liked the kitchen sink approach that I see first C++, now Rust moving towards, but I respect what Rust has managed to solidify into. It's a good language. That said, I still hate async with a passion, it makes the language more complex and not very elegant (i.e. function coloring). And now that I kno…

> (i.e. function coloring) I really wish people stopped using this concept, especially in the context of Rust because the `async fn`/“regular function” split is strictly equivalent to the `try_something()`/`something()` split (the first one being failible and returning a `Result` in case of failure). `Result`s and `Option`s are coloring the stack in exactly the same way a `Future` does (and `async` is pure syntactic…

There's consistent use of Result and Option in std, community agreement to do things that way, and it's pretty easy to use them.

Tons of stuff in std and many other crates don't use async. A lot of stuff is harder and more code to do async. A lot of it is much harder to read.

That's the difference.

Re: The Rust I wanted had no future

#397
post #388

Earlier quoted context omitted.

This is just one example, but moves are always bitwise, correct? So if I want an object to track all users of it in C++, I can just make a smart pointer for it whose copy/move/destruction operations notify the object about each event. How would you do that in Rust? (Similarly, what if I want a relative pointer?)

You can track all of this (things like Rc or Arc do) except move. Relative pointers are possible, depending on what you mean. Making this safe (e.g. preventing users of that type from breaking the relative addressing) is done via the Pin type.

> You can track all of this (things like Rc or Arc do) except move.

Which means you can't track this. Tracking moves is fundamental here.

> Relative pointers are possible, depending on what you mean.

Pretty sure they're not possible in the sense I mean, for the same reason as above - you need custom moves for this. I'm referring to a pointer (not an offset; a pointer) that automatically adjusts itself when copied or moved. So that it always points somewhere N blocks before/after itself.

These are just two examples, to get the point across that Rust actually lacks some capabilities (since somehow that surprises people). You can find more.

Re: The Rust I wanted had no future

#398
post #353
post #304

Earlier quoted context omitted.

Return either value or an EMPTY placeholder. Look Java did it. It returns a nullable value or Optional.

Then I have to check the result anyways. Same thing

No. In Rust check is there by default, with optional unchecked access. In C++ the safety is off by default and you have to remember to check.

It's like Yaml parsers, they had "load_yaml" which is unsafe and "safe_load_yaml" which is the secure option. Imagine no surprise when Rubyists went for shorter safe looking method and got their servers pwned.

Re: The Rust I wanted had no future

#399
post #6

Very interesting insight from Graydon, in hindsight I too would have loved something more towards ML than C++. I never liked the kitchen sink approach that I see first C++, now Rust moving towards, but I respect what Rust has managed to solidify into. It's a good language. That said, I still hate async with a passion, it makes the language more complex and not very elegant (i.e. function coloring). And now that I kno…

> I too would have loved something more towards ML than C++ I stopped paying attention to the language around 2012-2013 or so when the direction clearly steered towards the latter. You may want to check https://austral-lang.org/ out.

Nim is the closest to what I had originally hoped Rust would be. Especially Nim 2 with the new GC is really exciting. I suspect it will outperform all but the best hand tuned allocators.

It's even hard real time capable, which makes it potentially viable in scenarios like games where GC traditionally hasn't been.

Re: The Rust I wanted had no future

#400
post #370

Earlier quoted context omitted.

IDK about donuts. But consider a network request. The vast majority of the time is not spent in the CPU. Right?

Doesn't matter, donut was just an abstraction. s/eat a donut/make a network request/ Is "network request" a synchronous or asynchronous activity? It depends whether your code blocks and wait's until response (or timeout) or continues executing and handling it when it comes. It's property of the "attention" of the caller, not of activity itself.

But "can be gracefully executed asynchronously" is a property of an action.

Something that pegs the CPU to 100% because it's doing intense processing isn't a good candidate for async. Similarly, some code can cause issues when written in a non-streaming fashion. Take the following example (in python):

    x = [x for x in range(1_000_000_000)]
    y = (x for x in range(1_000_000_000))
If you spawn a bunch of async workers doing the first one concurrently, you'll OOM your system. If you spawn a bunch of async workers doing the second one concurrently, your system will be fine.

In other words, "async" is a label on a box of donuts that implies (though doesn't ensure, people can of course still do bad things) that the donut won't explode if you look away from it.

Post reply on HN