Live data from Hacker News

Fearless concurrency with Rust

blog.rust-lang.org

111–120 of 186 posts

Re: Fearless concurrency with Rust

#111

Can someone please write a Clojury lisp that compiles to Rust without immutability (by default) and concurrency primitives, since thread safety is guaranteed by the rust compiler? I love Clojure, but this would be a completely different beast, a crazed DRAGON probably. PS: I want a Dragon

Sounds like you want a Rust port of Shen[1]. AFAIK there are no real[2] efforts to do that... yet.

[1] http://shenlanguage.org

[2] https://github.com/michaelsbradleyjr/shen.rs

Re: Fearless concurrency with Rust

#112
post #14

Earlier quoted context omitted.

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.

Similarly, I quite don't understand what in the type signatures precisely tie MutexGuard to the result of access. Like, in the "Disaster averted" example the mutex section, how is it detecting that "error: `guard` does not live long enough"? I see that access returns a borrowed mutable T. But, how does the compiler know that that's borrowed from guard instead of a hypothetical second or third parameter or from some o…

What's going on here is a bit of shorthand. If you don't use the shorthand, the signature looks like:

    fn access(guard: &'a mut MutexGuard) -> &'a mut T;
This says that the incoming borrow and the returned borrows have identical scopes (officially called "lifetimes" in Rust; 'a here is a lifetime variable.) It's a very typical pattern: if you return some borrowed data, it generally comes from a borrow you were given, and the shorthand allows you to leave this implicit in cases where it's clear.

EDIT FOR CLARITY: in particular, you're saying that if you take a "sublease" from something you've already borrowed, that sublease is valid for no longer than the original lease. So for example if you borrow a field out of a borrowed structure, the access to the field can last no longer than you had access to the original structure. In this case, we're saying that access to the data lasts no longer than the lock is held.

I'd recommend http://blog.skylight.io/rust-means-never-having-to-close-a-s... if you want to get a bit more of a feel for how this works.

The details about the shorthand are here: https://github.com/rust-lang/rfcs/pull/141

Re: Fearless concurrency with Rust

#114

Earlier quoted context omitted.

>I think generics are poorly understood in general Perhaps by programmers (and the designers/maintainers of certain mainstream languages...), but there are some very strong models out there; we've had well-behaved parametric polymorphism à la Hindley-Milner for decades and Haskell's typeclasses are in my opinion a very well-thought-out approach to ad-hoc polymorphism (and which the more ambitious C++0x version of Con…

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.

Re: Fearless concurrency with Rust

#115
post #64

Earlier quoted context omitted.

"Should have done" is a silly phrase to use here -- Rust is attempting to advance the state of the art, Go was attempting to use only very-well-understood ideas to make a very-well-understood, simple language. Perhaps some day we will see a successor language that follows the philosophy of Go using the new stuff we understand thanks to Rust.

> Go was attempting to use only very-well-understood ideas to make a very-well-understood, simple language. Many of the ideas in go were not well understood and had only been demonstrated in research languages prior to go. Its concurrency model and associated primitives, and the automatic interface system were in roughly the same state then as Rust's new ideas are now. That said the ideas in Rust were not as well und…

Maybe not well understood by programmers but in the programming language world Go's ideas have been around for over 3 decades.

Re: Fearless concurrency with Rust

#116
post #108
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.

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 previously be solved. For other engineers, their job is to "make it work right"; they do not care about getting the software to work in the first place (which, at their organization, was probably solved years ago by someone who's now cashed out and sitting on a beach), they care about fixing all the cases where it doesn't work right, where the accumulated complexity of customer demands has led to bugs. The first is in charge of taking the software from zero to one; the second is in charge of taking the software from one to infinity.

For the former group, error checking just gets in their way. Their job is not to make the software perfect, it's only to make it satisfy one person's need, to replace something that previously wasn't computerized with something that was. Oftentimes, it's not even clear what that "something" is - it's pointless to write something that perfectly conforms to the spec if the spec is wrong. So they like languages like Python, Lisp, Ruby, Smalltalk, things that are highly dynamic and let you explore a design space quickly without getting in your way. These languages give you tools to do things; they don't give you tools to prevent you from doing things.

The second group works in larger teams, with larger requirements and greater complexity, and a significant part of their job description is dealing with bugs. If a significant part of the job description is dealing with bugs, it makes sense to use machines to automate checking for them. And so they like languages like Rust, C++, Haskell, Ocaml, occasionally Go or Java.

The two groups do very little work in common (indeed, most of the time they can't stand to work in the opposing culture), but they come together on programming message boards, which don't distinguish between the two roles, and hence we get endless debates.

Re: Fearless concurrency with Rust

#117

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 lifetimes and borrowing.

Re: Fearless concurrency with Rust

#118
post #64

Earlier quoted context omitted.

"Should have done" is a silly phrase to use here -- Rust is attempting to advance the state of the art, Go was attempting to use only very-well-understood ideas to make a very-well-understood, simple language. Perhaps some day we will see a successor language that follows the philosophy of Go using the new stuff we understand thanks to Rust.

> Go was attempting to use only very-well-understood ideas to make a very-well-understood, simple language. Many of the ideas in go were not well understood and had only been demonstrated in research languages prior to go. Its concurrency model and associated primitives, and the automatic interface system were in roughly the same state then as Rust's new ideas are now. That said the ideas in Rust were not as well und…

Go's concurrency primitives are rooted in decades-old research (CSP).

Its interface system is an implementation of structural typing, which may be even older.

You could maybe argue that neither had "industrial-strength" implementations, but that seems like a stretch.

Re: Fearless concurrency with Rust

#119

Earlier quoted context omitted.

> > (an explicit primary design goal, to the point where the Go compiler must be written to read each file exactly once[0], no more). > Same in Rust. Thanks to the module system, the Rust compiler never rereads a file more than once. As I said right at the beginning of my post, I'm not trying to compare Rust and Go directly, because I don't think that's meaningful. I'm explaining why these particular features would b…

> I would otherwise be interested in having a discussion about static analysis and hearing why you think it would not solve the problem Stack allocation isn't in the semantics of Go, so that's a pretty weird thing to use a basis of a static analysis. It's also not sound because of interfaces or closures. You would want something more like "fully by-value data with no pointers in it, no interfaces, no closures".

Not to mention no arrays or slices! This burned me pretty hard during my first week with Go.

Re: Fearless concurrency with Rust

#120
post #56

Earlier quoted context omitted.

I'm pretty sure Cyclone used both regions and borrowing in ~2005. But it was a research project and not meant for wide use.

I thought Cyclone only used regions, but I haven't read the paper in a while. (and dates from 2002 IIRC) It certainly had a big influence on Rust, we're fans of the work.

Cyclone definitely had borrowing. See section 3.1 of this paper: https://www.cs.umd.edu/~mwh/papers/ismm.pdf. Generally speaking, every attempt to use substructural types for resource management in a practical language has allowed for temporarily treating a restricted resource as unrestricted.
Post reply on HN