Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

I think the question is "what is the cost" of the more novel rust safety features? In my experience, the cost is pretty high.

When you set Rust next to, e.g. swift, swift is phenominally more productive and similarly performant. And it is also quite safe (relative to C) without having all of the Rust safety features that make me want to kill the borrow checker with a rusty spoon.

I really wish Rust walked back on the more esoteric forms of safety (like thread safety, which you can't really verify anyway, you just promise the compiler that it's safe) and it tried to drive a bargain like Swift.

Rust really isn't satisfied to adopt the safety features that are "fairly low effort", it wants to break new ground without really measuring developer cost (hard to do since it's not widely used). That's really my issue with it.



> When you set Rust next to, e.g. swift, swift is phenominally more productive and similarly performant. And it is also quite safe (relative to C) without having all of the Rust safety features that make me want to kill the borrow checker with a rusty spoon.

Swift is totally garbage collected: every object is atomically reference counted. (This is necessary for compatibility with Objective-C.) So Swift is essentially in the same category as Go, Java, and most other languages as far as memory management is concerned.

Garbage collection is simply not a cost that we wanted to pay with Rust, in order to reach performance parity with C++.

> I really wish Rust walked back on the more esoteric forms of safety (like thread safety, which you can't really verify anyway, you just promise the compiler that it's safe) and it tried to drive a bargain like Swift.

I don't understand "you just promise the compiler that it's safe". Rust prevents you from accessing data in a non-thread-safe way without a mutex or atomics. This is in fact something that just fell out of the memory safety features above and didn't require any extra features: see [1] for an elaboration on this point.

> Rust really isn't satisfied to adopt the safety features that are "fairly low effort", it wants to break new ground without really measuring developer cost (hard to do since it's not widely used).

We have been measuring developer cost all along, by writing hundreds of thousands of lines of code in the language as we've been developing it: the Rust compiler is written in Rust, and we've been developing Servo as well.

[1]: http://smallcultfollowing.com/babysteps/blog/2013/06/11/on-t...


Swift is not garbage collected in the slightest. ARC is not garbage collection.

http://sealedabstract.com/wp-content/uploads/2013/05/Screen-...

Once upon a time Objective-C had a real garbage collector but that temporary interlude has not, nor ever will be supported from Swift.

Finally, Swift objects (can be, as compiler decides) laid out on the stack, so unless you have some super sweet stack garbage collection technology you'd like to share with us, they aren't garbage collected.

In any case, I don't see what garbage collection has to do with safety or the borrow checker.

> I don't understand "you just promise the compiler that it's safe"

Perhaps you'd like to read the Rust Book:

> When a type T implements Sync, it indicates to the compiler that something of this type has no possibility of introducing memory unsafety when used from multiple threads concurrently.

I think "you just promise the compiler that it's safe" is an accurate summary of that feature.

> We have been measuring developer cost all along, by writing hundreds of thousands of lines of code in the language as we've been developing it: the Rust compiler is written in Rust, and we've been developing Servo as well.

Would you be satisfied if you wrote a language that is productive only for language designers writing web browsers and compilers? Because that is all your measurements prove.

I'm telling you, as an intermediate Rust developer doing neither of those things, that I am not sure if I am more productive in Rust or C. Rust is certainly safer, but I am not convinced that safety is worth returning to C-like productivity. Performance is, but I can achieve good performance in Swift.

Rust assumes that I value performance and safety equally; e.g. that I am willing to give up productivity for either one. In reality I am only willing to give up productivity for performance. There are some low-hanging safety fruit that I want (like optionals) but the higher-cost fruit like multithread safety I don't want. I think those features are Bad (TM).


> Swift is not garbage collected in the slightest. ARC is not garbage collection.

Reference counting and tracing garbage collections are two ends of the spectrum of ways to handle dynamic allocation graphs (aka "garbage collection").

http://www.cs.virginia.edu/~cs415/reading/bacon-garbage.pdf

> In any case, I don't see what garbage collection has to do with safety or the borrow checker.

The borrow checker is what allows Rust to be safe and performant without garbage collection. It's literally the feature that gives Rust that power.

> I think "you just promise the compiler that it's safe" is an accurate summary of that feature.

A lot of programming (not just in Rust) is like this: the programmer promises that the library interface they expose does what they say it does, promise that any use of ctypes (in Python, for instance) won't corrupt the interpreter state, etc.

This isn't much different. The standard library will follow those that guidelines (i.e. something in the standard library implements Sync if and only if it satisfies that definition) and we expect library/application authors to do the same. The rule is to provide the programmer with assistance, it's not just to be annoying. It's your own fault if you shoot your own foot off by disobeying it (hence throwing away the assistance the compiler can provide you).

In any case, Rust has the `unsafe` keyword, a structured mechanism for making promises to the compiler, allowing one to easily see the possible locations that could cause memory corruption/unsafety. Overriding the compilers judgement that a type isn't thread-safe is no different: it requires `unsafe`.

> the higher-cost fruit like multithread safety I don't want. I think those features are Bad (TM).

FWIW, I think the multithreading safety is the really interesting and awesome part of Rust. Pretty much no other industry language attempts to tackle the problem of writing safe, low-level, high-performance, highly-parallel/highly-concurrent programs. Rust's system for this is quite general and flexible.


> Swift is not garbage collected in the slightest. ARC is not garbage collection.

Arguing about definitions is not going to be productive, but that slide does not present the definition of garbage collection used by most people who specialize in memory management. Reference counting is not tracing garbage collection, but it is garbage collection. See the excellent memorymanagement.org glossary [1], Wikipedia [2], or David Bacon's papers [3], etc. etc.

> Finally, Swift objects (can be, as compiler decides) laid out on the stack, so unless you have some super sweet stack garbage collection technology you'd like to share with us, they aren't garbage collected.

Escape analysis is a common technique to reduce allocations (used in Java and Go for example) but it falls down a lot in practice: it is typically unable to deal with higher-order functions, for example. It is hard to predict when it happens, and that's not a cost we wanted to pay. (Furthermore, in a highly-optimized generational garbage-collected system, reducing allocations doesn't help performance very much, because bump allocation in the nursery is so fast: one of the downsides of Swift's system is that allocation is much slower than in a generational tracing system, so it has to rely on escape analysis to regain some of the performance loss. This was needed for compatibility with Objective-C though, so it's understandable.)

> In any case, I don't see what garbage collection has to do with safety or the borrow checker.

It's central to the borrow checker's existence (and the lifetime system in general). Memory safety without garbage collection is a central design goal of Rust, and the borrow checker is part of the means to achieve that. We could have just used garbage collection (like Swift and most other languages did), but then we would suffer a performance loss.

> I think "you just promise the compiler that it's safe" is an accurate summary of that feature.

No, that's not accurate. Sync is an unsafe trait [4]. That means that you cannot implement it without opting into the unsafe sublanguage of Rust by typing "unsafe".

The unsafe sublanguage is primarily used to implement features (such as vectors or smart pointers) that would otherwise have to be built in to the compiler. Since the compiler implementation itself is not proved correct in any production compiler, this doesn't result in a net loss of safety compared to any other language. You can turn off the unsafe sublanguage entirely via an attribute or a compiler switch, and if you do so then thread safety should be absolute: if you can violate thread safety, it's a compiler bug!

Many other languages, including Swift, have unsafe "escape hatches". That doesn't compromise their safety, because you can avoid them and turn them off entirely.

> Would you be satisfied if you wrote a language that is productive only for language designers writing web browsers and compilers? Because that is all your measurements prove.

While it would be flattering to assume that the Rust team wrote the 100,000 lines of Servo, we aren't that productive :) Rather, much—perhaps most at this point—of Servo has been written by people who have never touched a line of code in rustc. In fact, a lot of it has been written by people who have never done systems programming before! (It's not just Servo: the authors of Skylight, for example, who use Rust in production, were not systems programmers or compiler hackers before coming to Rust.)

> I'm telling you, as an intermediate Rust developer doing neither of those things, that I am not sure if I am more productive in Rust or C. Rust is certainly safer, but I am not convinced that safety is worth returning to C-like productivity. Performance is, but I can achieve good performance in Swift.

> Rust assumes that I value performance and safety equally; e.g. that I am willing to give up productivity for either one. In reality I am only willing to give up productivity for performance.

Swift's approach—garbage collection via pervasive atomic reference counting—has significant performance costs over that of Rust. See Hans Boehm's slides [5]: Swift's approach is equivalent to "Boost thread safe", while Rust's approach is "C expl. free". (Note that those slides are old and do not take into account modern scalable mallocs like tcmalloc and jemalloc, the latter of which Rust uses: since these slides were published, the performance of thread-safe malloc has gotten much closer to thread-unsafe malloc, while the cost of atomic reference counting has stayed unchanged except by advances in atomic instruction performance at the CPU level.)

> There are some low-hanging safety fruit that I want (like optionals) but the higher-cost fruit like multithread safety I don't want. I think those features are Bad (TM).

The thread safety features fell out of the memory-safety-without-GC features. It's an added bonus: we could remove it and switch to thread safety for all objects, but there's no reason to, because opting into thread safety only when you need it is a massive performance gain. So again, the thread safety just boils down to memory safety without garbage collection. Swift opted into garbage collection, which is a totally defensible choice given their constraints, but let's be candid about the tradeoffs: Swift is not in Rust's category at all.

[1]: http://www.memorymanagement.org/glossary/g.html#term-garbage...

[2]: http://en.wikipedia.org/wiki/Garbage_collection_%28computer_...

[3]: http://researcher.watson.ibm.com/researcher/files/us-bacon/B...

[4]: http://doc.rust-lang.org/std/marker/trait.Sync.html

[5]: http://hboehm.info/gc/nonmoving/html/slide_11.html


Well, Swift uses reference-counting. There aren't GC pauses, for example.


Not to turn this into an argument about definitions, but reference counting is a form of garbage collection [1]—tracing garbage collection is the one that has pauses (but of course has many advantages over reference counting).

[1]: http://www.memorymanagement.org/glossary/g.html#term-garbage...


I know it's a form of garbage collection, yes. My point is that it lacks some of the issues that other types of collectors have.


It's not just a question of definitions: I wouldn't characterize reference counting as "striking a bargain" at all. RC is just a form of garbage collection, and in its atomic form (like in Swift) it has serious downsides relative to tracing GC. Reference counting helps latency (important in mobile, which is why Apple's choice is defensible) but it pays enormous costs in throughput when compared with tracing (not to mention the problem of cycles), so much so that tracing is usually considered the superior approach unless you have special requirements. Rust's approach of manual memory management is designed to eliminate the tradeoff by allowing prompt reclamation without all the overhead of managing reference counts, which is why it's in a separate category entirely.




Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: