Live data from Hacker News

Fearless concurrency with Rust

blog.rust-lang.org

121–130 of 186 posts

Re: Fearless concurrency with Rust

#121
post #108

Earlier quoted context omitted.

Sigh. We build machines to automate the repetitive, to eliminate the daily drudgery and to repeat steps with perfection (that we would repeat with perfection ourselves if only we were as focused as a machone). So why do we keep finding ourselves arguing that a lazy compiler, which offloads the work of a machine on to a dev team, is an acceptable compromise?

Meta-comment: I believe the difference in opinion here (which seems to recur, over and over, and has for decades) is because the job title of "software engineer" actually encompasses many different job duties. For some engineers, their job is to "make it work"; they do not care about the thousand cases where their code is buggy, they care about the one case where it solves a customer's problem that couldn't previousl…

My point was: tools that prevent you from doing things should not do that without explicit permission. Because thinking is hard and any interruption by a tool or a compiler will impose unnecessary cognitive load and will make it even harder, which may lead to a logical mistake. It is much better to deal with the compiler after all the thinking is done, not during.

Re: Fearless concurrency with Rust

#122
post #79

Earlier quoted context omitted.

> The fact is, these "idioms and best practices" will not be followed perfectly on projects of any reasonable size if they are not enforced by code. Why would you not enforce them with code? Compiler shall not be an obstacle to a man. We tried enforcing things before, many times. Things got abandoned.

Agreed. But every production language that I'm aware of has an out that allows you to escape its type system, with the exception of languages whose type systems are intended to uphold strong security properties and verification languages that feature decidable logics. I can't remember for sure, but I think even Coq--which is eminently not a language designed for everyday programming--may diverge if you explicitly opt…

I think it's worth clarifying that Rust's `unsafe` doesn't opt-out of the core type system per se, it allows the use of a few additional features that the compiler doesn't/can't check. I think this distinction is important because, as you say, `unsafe` isn't very uncommon and so it is nice that one still benefits from the main guarantees of Rust by default inside `unsafe`. :)

Re: Fearless concurrency with Rust

#123
post #23

Earlier quoted context omitted.

Preventing deadlocks is not an unsolvable problem. Linear-session-typed process calculi are guaranteed deadlock-free and race-free. (The connection with Rust's ownership type-system makes me wonder if there might be some way to backport this guarantee to Rust, but I suspect the connection doesn't go far enough.) This comes at a price, however: certain process topologies are impossible to construct, and there's no way…

The safe subset of Rust (which is more-or-less linearly typed with elided drops) is indeed deadlock-free. Features like mutexes are written using the unsafe sublanguage because shared memory concurrency is useful. Because potential deadlocks are opt-in rather than opt-out, it's not unreasonable to imagine that future extensions to Rust (or some other language in the same mold) could bridge this gap in a practical way…

FWIW, transitively-safe Rust is quite uninteresting as an actual programming language, since you can essentially only use some arithmetic and simple user-defined data types. There's no IO and no core data structures like Vec: `unsafe` is designed to be used as a building block to create safe interfaces and the distinction between safe things implemented in the language itself and safe things implemented in libraries (especially the standard library) is fuzzy... and even then, the compiler can be regarded as one huge `unsafe` block.

Of course, what you say is perfectly true, the Rust language itself has no threads or concurrency, and hence is automatically dead-lock free.

Re: Fearless concurrency with Rust

#124
post #123

Earlier quoted context omitted.

The safe subset of Rust (which is more-or-less linearly typed with elided drops) is indeed deadlock-free. Features like mutexes are written using the unsafe sublanguage because shared memory concurrency is useful. Because potential deadlocks are opt-in rather than opt-out, it's not unreasonable to imagine that future extensions to Rust (or some other language in the same mold) could bridge this gap in a practical way…

FWIW, transitively-safe Rust is quite uninteresting as an actual programming language, since you can essentially only use some arithmetic and simple user-defined data types. There's no IO and no core data structures like Vec: `unsafe` is designed to be used as a building block to create safe interfaces and the distinction between safe things implemented in the language itself and safe things implemented in libraries…

Yes, it's somewhat banally true, but it's an important subset of the language because the guarantees of transitively-safe Rust represent a baseline for what you can ultimately guarantee in the language. Work like Patina (ftp://ftp.cs.washington.edu/tr/2015/03/UW-CSE-15-03-02.pdf) is useful for that reason. Transitively-safe Rust may also independently fulfill a useful role in the language; e.g., it is a candidate for the subset acceptable in constant expressions.

Re: Fearless concurrency with Rust

#125

everything mentioned can be done in C++11 and lthread_cpp http://lthread-cpp.readthedocs.org

What is interesting is not so much that Rust has shared-memory concurrency (BTW, isn't lthread a M:N threading library? Everything in the article is 1:1) but that it can make this statically safe. Perhaps I am missing something, but I see no evidence from your repository that lthread enforces any of the static safety guarantees discussed in the article, which is not surprising as many of them fundamentally depend on…

Possible M:N.. by default it's 1:1. It's 1 lthread scheduler per actual pthread.

static safety guarantees can come with auto pointers (unique_ptr in particular). This is why I said lthread_cpp & C++11.

Re: Fearless concurrency with Rust

#126

Earlier quoted context omitted.

What is interesting is not so much that Rust has shared-memory concurrency (BTW, isn't lthread a M:N threading library? Everything in the article is 1:1) but that it can make this statically safe. Perhaps I am missing something, but I see no evidence from your repository that lthread enforces any of the static safety guarantees discussed in the article, which is not surprising as many of them fundamentally depend on…

Possible M:N.. by default it's 1:1. It's 1 lthread scheduler per actual pthread. static safety guarantees can come with auto pointers (unique_ptr in particular). This is why I said lthread_cpp & C++11.

std::unique_ptr is a significant improvement over prior options, but it can neither ensure correct usage of a mutex (in the sense that it can't cause a data race) nor preserve data race safety for references into another thread's stack. Both of these rely on Rust's ability to limit reference lifetimes, which C++11 doesn't really have (C++14 has an extremely limited form of it in rvalue references, but it's not sufficient to replicate what's in this article). unique_ptr also can't really statically guarantee uniqueness (it's done at runtime instead), meaning it doesn't quite work with channels; and in combination with other C++ features (such as references or shared_ptr) you can also see data races through it, since it doesn't prevent mutation; thus, it isn't able to guarantee safety for use with channels either.

Re: Fearless concurrency with Rust

#127
post #114

Earlier quoted context omitted.

Concerning std::allocator_traits, it reflects a deeper limitation of the language rather than just a library design flaw. If you had HKT, you could pass std::allocator to a template. You can't do that, you can only pass std::allocator for some concrete T. Equivalently, in Haskell, you can pass IO as a type parameter, so you don't see the same kludges. I definitely agree with the sentiment about subtype polymorphism.

You can actually pass std::allocator to a template: template foo {}; template class F> struct bar { F f; }; bar b; This is painful to do with a lot of the STL like vector, because they have a lot of default template arguments and there's no implicit currying. I haven't investigated it but variadic template template arguments might help there, though.

>I haven't investigated it but variadic template template arguments might help there, though.

They do:

    template  class Container, typename T>
    Container  fin (T n) {
        Container  set;
        for (T i = 0; i  (10))
            std::cout 

Re: Fearless concurrency with Rust

#129
post #86
post #12

Rust's ownership model, and the borrow checker that enforces it, are a major breakthrough in language design. It's so simple, yet it solves so many problems. This is what Go should have done. Then Go's "share by communicating, not by sharing" would be real, not PR. Go code often passes references over channels, which results in shared memory between two threads with no locking. In Rust, when you do that, you pass own…

When Go was first announced in 2009, I thought "this is a nice idea, but I really wish it had generics and non-nullable references". Then Rust was announced a few months later, and I thought "wow, this is what Go should have been." However, in the intervening time, Rust has diverged farther from Go. It no longer has green threads nor emphasizes message-passing based concurrency. In addition, Go was ready to use much…

Well, let's also not forget that a big factor in Go's success is Google.

Google has much deeper pockets than Mozilla to build a language and infrastructure.

Re: Fearless concurrency with Rust

#130

Earlier quoted context omitted.

Possible M:N.. by default it's 1:1. It's 1 lthread scheduler per actual pthread. static safety guarantees can come with auto pointers (unique_ptr in particular). This is why I said lthread_cpp & C++11.

std::unique_ptr is a significant improvement over prior options, but it can neither ensure correct usage of a mutex (in the sense that it can't cause a data race) nor preserve data race safety for references into another thread's stack. Both of these rely on Rust's ability to limit reference lifetimes, which C++11 doesn't really have (C++14 has an extremely limited form of it in rvalue references, but it's not suffic…

unique_ptr transfers ownership. No 2 threads can be working on the same object unless you go out of our way to cheat unique_ptr behavior.

Statically or at runtime guarantees don't buy me much. Regarding mutations, const and copy/move constructors give you want u want. Generally, all you need to do is have 1 thread create an std::unique_ptr object and pass it to the channel for other thread to pick it up.

Post reply on HN