Earlier quoted context omitted.
We may end up adding linear types, not just affine, to Rust as well: https://github.com/rust-lang/rfcs/issues/814
From the RFC you linked: "First, the `linear` attribute as described here does not create true `linear` types: when unwinding past a `linear` type, the `linear` attribute will be ignored, and a `Finalize` trait could be invoked. Supporting unwinding means that Rust's linear types would in effect still be affine."
Fearless concurrency with Rust
21–30 of 186 posts
Re: Fearless concurrency with Rust
#22Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? To explain, say that I have some code that locks A, then locks B, then does something, and another bit of code that locks B, then locks A, then does its thing. There's a race condition that can happen where one thread has A and the other thread has B. This has bitten me so much that I avoid fine-grained locking when possibl…
> Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? This is the difference between a data race and a race condition. We can't generally prevent deadlocks, I would imagine that's (like all race conditions) is an unsolvable problem at the language level. Maybe some PhD will prove me right or wrong, though...
Re: Fearless concurrency with Rust
#23Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? To explain, say that I have some code that locks A, then locks B, then does something, and another bit of code that locks B, then locks A, then does its thing. There's a race condition that can happen where one thread has A and the other thread has B. This has bitten me so much that I avoid fine-grained locking when possibl…
> Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? This is the difference between a data race and a race condition. We can't generally prevent deadlocks, I would imagine that's (like all race conditions) is an unsolvable problem at the language level. Maybe some PhD will prove me right or wrong, though...
In general, problems of "guarantee property X" can almost always be solved with a sufficiently advanced type system, but at the cost of (a) inventing and using a sufficiently advanced type system and (b) disallowing some perfectly good programs.
Re: Fearless concurrency with Rust
#24Earlier quoted context omitted.
> Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? This is the difference between a data race and a race condition. We can't generally prevent deadlocks, I would imagine that's (like all race conditions) is an unsolvable problem at the language level. Maybe some PhD will prove me right or wrong, though...
Deadlocks can be statically prevented by ensuring that all code paths acquire locks in the same order. However, Rust's type system is not capable of enforcing that by itself (except maybe in some very limited cases). Some other substructural type systems (e.g. http://en.wikipedia.org/wiki/Substructural_type_system#Order... ) might be up to the task, but I'm far from an expert in this area.
Re: Fearless concurrency with Rust
#25Earlier quoted context omitted.
> Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? This is the difference between a data race and a race condition. We can't generally prevent deadlocks, I would imagine that's (like all race conditions) is an unsolvable problem at the language level. Maybe some PhD will prove me right or wrong, though...
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…
I guess what I was trying to get at is that 'race conditions' can fall under the same kinds of errors as logic errors. This is the way that people usually attack the phrase "if it compiles, it works."
Re: Fearless concurrency with Rust
#26Earlier quoted context omitted.
> Sorry if I'm missing something obvious, but how do these locks stop a deadlock from happening? This is the difference between a data race and a race condition. We can't generally prevent deadlocks, I would imagine that's (like all race conditions) is an unsolvable problem at the language level. Maybe some PhD will prove me right or wrong, though...
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…
Re: Fearless concurrency with Rust
#27Just a comment: I've noticed Rust literature generally errs on feeling a bit dense and esoteric, which might make things less approachable for some. Then again, that does depend on your target audience. This article doesn't make me feel immediately "fearless" about concurrency, and I'm a fairly experienced programmer and a fan of the language. Perhaps it would have been wiser to start with an approachable example and…
> Also, are there any plans to integrate tutorial-style guides similar to those from Rust for Rubyists into the Rust book? I'd been waiting for beta to drop to do a re-organization of the TOC of the book. You can see it on nightly here: http://doc.rust-lang.org/nightly/book/ I've carved out a whole section, "Effective Rust", specifically for this kind of thing. I'm looking for a better name than "Effective Rust", sin…
Re: Fearless concurrency with Rust
#28Earlier 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…
Ah, thanks for that, I'll look into it. I guess what I was trying to get at is that 'race conditions' can fall under the same kinds of errors as logic errors. This is the way that people usually attack the phrase "if it compiles, it works."
I would define a race condition as "an error due to nondeterministic concurrency". If you ban nondeterminism, for example, race conditions are impossible. In practice, nobody wants to ban nondeterminism, so races creep in. There might be smarter ways to eliminate races (ways of only allowing benign nondeterminism), though. So I'm not sure that practical languages without race conditions are an unachievable goal, just a difficult one. Give it another 20 years and we'll see where we're at. :)
Re: Fearless concurrency with Rust
#29Rust'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…
> Go code often passes references over channels, which results in shared memory between two threads with no locking
Having a complex type system would cut into compile times (an explicit primary design goal, to the point where the Go compiler must be written to read each file exactly once[0], no more).
As for the code you're referring to, Go is not designed to be a language which prevents you from shooting yourself in the foot with provable code. It's designed to be a language which makes it reasonably easy to be sure you haven't, as long as you follow the general idioms and best practices. What you're describing here is definitely not one - I can think of a few instances in which pointers might be reasonably passed over a channel, but they're few and far between.
Also, I would think it's pretty obvious that once you've sent something over a channel you shouldn't try and write to it anymore[1]. Do you have an example of the code you're referring to?
[0] well, technically "at most once", since some files can be skipped entirely.
[1] I'd need to think about this, but I don't think it'd be difficult to detect this statically[2] at compile-time and enforce that stack-allocated rvalues into channels are never used again in the same scope. It's definitely possible to extend `go vet` to handle this, and it may even be possible to write this in as a compiler error in a future version of Go.
[2] Incidentally, one of the reasons that it's so easy to do reliable static analysis on Go code (compared to other languages) is that the grammar is incredibly simple - it's almost entirely context-free, which is very rare among non-Lisps. Having a more complex type system usually requires at least some additional syntax to along with this, which means you'd have to start sacrificing this design goal as well in order to create a more elaborate type system.
Re: Fearless concurrency with Rust
#30I am slightly confused about why the MutexGuard type is required in the locking example. Why can locking a lock not just return &mut? The API as written does so eventually anyway, through access(). I guess the API as written allows you to call access() multiple times, but I do not see how this is a useful property if the mutex stays locked for the entire scope of the MutexGuard anyway.
The key is that the MutexGuard is responsible for unlocking (and it does so automatically on destruction). That way, you're tying the scope for the &mut reference to the scope in which the lock is actually held.