Live data from Hacker News

Why Rust closures are somewhat hard

stevedonovan.github.io

51–60 of 92 posts

Re: Why Rust closures are somewhat hard

#51
post #48

Everything that's hard in Rust could be solved by GC. With Rust, programmers have to spend most of their mental energy worrying about management of memory, which has largely been automated already. I always go back to this quote from Andrei Alexandrescu (creator of D): A disharmonic personality. Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery of men with…

> You just limited the set of programs you can write to those that can be written in the block-lifetime-scoped manner, which is smaller than the set of good programs (see: pretty much any graph-heavy data structures). Given that most of my Rust programs have involved graph-heavy data structures, I'd like to see you explain why it's impossible for me to have written what I have written.

Not impossible, just harder. Ceteris paribus, it would have been easier to write those programs in Python or Java.

It's not like this is not well-known. Rust users admit it. GUIs are hard to write in Rust because of the limitations of RAII+borrow checker based memory. You have to rely on ref counted pointers which can become very complicated to deal with in cyclic dependencies and long-lived references common in GUIs. This problem is not unique to Rust either. C++ makes it hard to write GUIs too, but hacks are used to get around the language like Qt's moc or Microsoft's old CLI extensions to C++.

All non-GC languages are crippled for application programming. Sure, there are domains where GC cannot ever work, like signal processing or kernel dev. In these places I'd much rather see Rust used than C++.

Re: Why Rust closures are somewhat hard

#52
post #51

Earlier quoted context omitted.

> You just limited the set of programs you can write to those that can be written in the block-lifetime-scoped manner, which is smaller than the set of good programs (see: pretty much any graph-heavy data structures). Given that most of my Rust programs have involved graph-heavy data structures, I'd like to see you explain why it's impossible for me to have written what I have written.

Not impossible, just harder. Ceteris paribus, it would have been easier to write those programs in Python or Java. It's not like this is not well-known. Rust users admit it. GUIs are hard to write in Rust because of the limitations of RAII+borrow checker based memory. You have to rely on ref counted pointers which can become very complicated to deal with in cyclic dependencies and long-lived references common in GUIs…

This indictment makes little sense to me considering that, outside the Rust compiler itself, the largest early and still ongoing use case for Rust was/is Servo. A web browser engine, which is predominantly a thing that's dealing with multitudes of graph-shaped problems.

:confused:

Re: Why Rust closures are somewhat hard

#53
This article does a great job explaining the subtleties about rust closures.

A subtle point often missed is that if you want the anonymous structure of your closure itself to own a value, so that you can have a closure with a `'static` lifetime (which lives forever) that still could be called multiple times, you must use move keyword. If you just move the values into the closure manually, your closure will be a `FnOnce` since the compiler will mistakenly believe that you want to move that value each time the closure gets invoked, which can only happen once if the moved value doesn't implement `Copy`. In constrast, if you use the `move` keyword, compiler will correctly move the value into the anonymous structure of the closure itself during its construction, and the closure will be a `FuMut` and/or `Fn` as long as you don't consume the said value in the closure.

Re: Why Rust closures are somewhat hard

#54

This article does a great job explaining the subtleties about rust closures. A subtle point often missed is that if you want the anonymous structure of your closure itself to own a value, so that you can have a closure with a `'static` lifetime (which lives forever) that still could be called multiple times, you must use move keyword. If you just move the values into the closure manually, your closure will be a `FnOn…

https://www.snoyman.com/blog/2018/11/rust-crash-course-05-ru...

Re: Why Rust closures are somewhat hard

#55
post #51

Earlier quoted context omitted.

Not impossible, just harder. Ceteris paribus, it would have been easier to write those programs in Python or Java. It's not like this is not well-known. Rust users admit it. GUIs are hard to write in Rust because of the limitations of RAII+borrow checker based memory. You have to rely on ref counted pointers which can become very complicated to deal with in cyclic dependencies and long-lived references common in GUIs…

This indictment makes little sense to me considering that, outside the Rust compiler itself, the largest early and still ongoing use case for Rust was/is Servo. A web browser engine, which is predominantly a thing that's dealing with multitudes of graph-shaped problems. :confused:

Have you looked at the issue tracker for Servo? The bugs and pain points are enlightening. Plus, Servo isn't even used in production! The strategy has been to move parts of it. AFAIU, the most complex piece so far has been the CSS engine. That's nothing to sneeze at, but still. I recently wrote a full PKIX X.509 DER decoder in LPeg in a couple nights of hacking; have fun doing that (or writing anything equivalent to LPeg[1], for that matter) in a language without GC. It's absolutely possible, just like it's possible to implement it in ATS or Coq, but that's not the point of debate.

That said, it's one thing to admit the costs of Rust's model. It's another to argue about the implications of that cost--i.e. the degree to which it makes Rust non-viable long-term. On that point I have no opinion, except to say that for complex application development I've been very happy using Lua as a glue language, and many others have been happy using GC'd languages for complex logic. But that's more of a neutral factoid as it both diminishes Rust's relative costs and benefits. Whether it augurs in favor of Rust or not depends on your starting point. Plus, language success is less dependent on merit than we'd like to believe.

[1] Note that LPeg is far more than a PEG engine (like Rust pest), as strict PEG engines are incapable of parsing DER, which is context-sensitive. In addition to its extensions (e.g. runtime matches), what makes LPeg so simple is that you don't even need intermediate graph representations. You can transform subtrees in the grammar inline, mixing function transforms and intermediate captures to your hearts content. This is difficult to explain and more difficult to appreciate until you see and use it in action.

Re: Why Rust closures are somewhat hard

#56
post #48

Everything that's hard in Rust could be solved by GC. With Rust, programmers have to spend most of their mental energy worrying about management of memory, which has largely been automated already. I always go back to this quote from Andrei Alexandrescu (creator of D): A disharmonic personality. Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery of men with…

"You just limited the set of programs you can write to those that can be written ..."

Yes! That's awesome! I want the set of programs I can write to be small, but still large enough to contain correct programs.

For example, I really like statically typed languages! But what is static typing? It's rules that reduce the set of valid programs. In a dynamically typed language, 'def double(x): x*2; double(os.Open("foo"))' or other such nonsense is a valid program that errors out at runtime reliably. In a statically typed language, that program is not valid. Woo! That's a whole class of programs that do bad stuff which aren't valid anymore!

If rust restricts the set of valid programs to those that structure the ownership of data more rigidly, I'll take it!

I do realize that rust has escape hatches that let you model those things when you need to, but I'll gladly take a language that pushes programmers away from difficult to reason about data-ownership-models even if it doesn't prevent all such cases.

Re: Why Rust closures are somewhat hard

#57
post #31

There's a lot of confusion about this. A lambda is just a function without a name. (This feature tends to come with special syntax, although it doesn't have to.) A nested function is a function defined inside another function which can access the variables of the enclosing function. (A nested function can be a lambda, but it doesn't have to be. Some languages have named nested functions. A lambda doesn't have to be a…

I think the OP makes it clear that this nuance is actually quite tricky in a native systems language like Rust. A good example in C++ would be: - A function (non capturing/lambda) is created with auto f = [] { ... }; - A function (capturing/closure) is created with auto s = "..."; auto f = [&] { s; ... }; In source code both of those look similar and you can even define them with the same type: std::function However,…

I’m pretty sure that the generated assembly for both your examples written as-is is the same. The optimizer should see through the lambda sugar unless the example gets weird or you type-erase via std::function.

I think your broader point still holds but perhaps could do with a clearer example

Re: Why Rust closures are somewhat hard

#58
post #48

Everything that's hard in Rust could be solved by GC. With Rust, programmers have to spend most of their mental energy worrying about management of memory, which has largely been automated already. I always go back to this quote from Andrei Alexandrescu (creator of D): A disharmonic personality. Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery of men with…

If you want a garbage-collected language, there's already literally a thousand of them out there. Including dozens that are more popular than Rust.

Re: Why Rust closures are somewhat hard

#59
post #48

Everything that's hard in Rust could be solved by GC. With Rust, programmers have to spend most of their mental energy worrying about management of memory, which has largely been automated already. I always go back to this quote from Andrei Alexandrescu (creator of D): A disharmonic personality. Reading any amount of Rust code evokes the joke "friends don't let friends skip leg day" and the comic imagery of men with…

Every GC is a trade off. You can't replace RAII with GC without losing some control. No matter how much you innovate in it, you have to pay with something. That's the whole point of GC after all.

Here is a good read about it: https://blog.plan99.net/modern-garbage-collection-911ef4f8bd...

Re: Why Rust closures are somewhat hard

#60
post #25

Earlier quoted context omitted.

Maybe you just miscommunicated, but you absolutely can use generic parameters in a return type: https://doc.rust-lang.org/nightly/std/iter/trait.Iterator.ht... ... and `impl Trait` exists to be able to have return types which are difficult, verbose, or impossible to name.

Yes, I think he meant that it would be a bad idea to lock all of the type parameters to the same type, because all closures have different types. So you wouldn't be able to do something like this compose(|x| x, |x| x) because the closures have the same type.

Because the closures don't have the same type, if I'm following you correctly.
Post reply on HN