11 ms·
Rust for C++ programmers – part 5: borrowed references
- ExpiredLink 13y agoThis 'ownership semantics' of pointers in Rust is just the wrong kind of abstraction. At least for a language nascent in 2014 AD.
- steveklabnik 13y agoCan you expand on why?
- eq- 13y agoI disagree. Even in 2014 we have a place for different kinds of new languages. If we didn't, the likes of C++ would live forever with all their shortcomings.
- ben0x539 13y agoReferences are non-owning pointers though. There's plenty of conceptual space for non-owning smartpointers too.
- pcwalton 13y agoIt's what allows Rust to have memory safety without garbage collection, which is something that systems programmers still care quite a bit about in 2014 AD.
- ExpiredLink 13y agoRust requires the programmer to do manually what the compiler could do for him - of course without garbage collection.
- azth 13y agoGC is not the answer to everything.
- scott_s 13y agoI'm not sure what you're trying to say. Perhaps I can try to sum up my view (and what I think is the view of many other people on this thread): If you start from the premise that garbage collection is not an option in some circumstances, and you want to maintain memory safety, then I think you inevitably end up in a situation where programmers must make their memory access patterns explicit. Rust achieves this through its type system. My guess is that you're disagreeing with the above premise.
- pcwalton 13y agoHow could the compiler achieve safe memory management without any annotations, runtime overhead, or garbage collection? I would be interested in answers to this question, but they are not obvious to me after years of thinking about this problem :)
- jasode 13y agoThe short replies from ExpiredLink lead others to misinterpret his response as pro-GC and therefore the downvotes but now that I've read all his other comments in this thread, I think I've pieced together what his actual thesis is: without using any runtime GC, a sophisticated enough compiler should have enough knowledge from analyzing the source code to "automatically" know the type of memory management classification for any variables. The programmer shouldn't have to manually annotate them. I'm not a compiler theory expert but my hunch is that ExpiredLink's premise is wrong. I'm guessing that any non-trivial program requires a priori knowledge from the programmer's mind to properly inform the compiler which variables do what and when. To use an analogy in the spirit of ExpiredLink's thinking: we don't manually annotate statements such as "int [register_cx] bank_account = balance + deposit" We don't have to "annotate" statements with micro-details such as specific x86 registers bx,cx,dx,etc. "It would be the wrong abstraction" to borrow his wording. The compiler assigns registers on our behalf. It's been doing that for decades. I'm guessing memory safety is a much more difficult problem. If perfectly optimal register allocation is an NP-complete problem, it seems safe to assume that compiler generated safety annotations for memory is NP-complete. Therefore, the proof for ExpiredLink would be a short example source code that demonstrates how a priori knowledge is unavoidable to achieve extra memory safety and maintain C/C++ performance. The only other option is some mythical compiler that runs for 10 hours analyzing 1,000 lines of source code trying to trace all possible memory accesses only to come up with a suboptimal solution to an NP-complete problem. And on top of that, would the compiler have to be so sophisticated as to have to create a VMware/Virtualbox virtual machine to simulate all memory accesses? I have no idea.
- shmerl 13y agoI think the problem with this is that even if compiler can somehow semi-magically deduce that, it can be still be not what the author really intended. So making memory ownership semantic explicit improves clarity and avoids any kind of ambiguity and unintended logic. Also, it helps communicating the intention to others who might read or maintain the code later. Obscuring this is not helpful at all.
- general_failure 13y agoNot sure why you are being downvoted. I agree with you, the whole thing seems archaic. Downvoters care to comment on why this is relevant to a modern programming language and try to convince us (and not the other way around)? Give me a good example of why I should care. Performance? Do you have numbers?
- pcwalton 13y agoIf you mean "do you have numbers as to why you might not want GC in all scenarios", yes. http://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf http://people.cs.umass.edu/~emery/pubs/gcvsmalloc.pdf
- pkolaczk 13y agoGenerally I agree that you don't want GC in all scenarios, but the paper you cite has several flaws which makes its conclusions very far from truth. 1. It is based on non-production JVM and does not use the same algorithms that are used in production level VMs. There is a huge performance difference between any GC from 1990s and modern generational GC used in production-level VMs. 2. Some part of the experiment involved simulation. You must be very careful with extrapolating simulation results onto real world. Actually someone on the Internet rerun one of the same experiment using non-simulated VM and got totally different results, but now I can't find that blog post :( 3. It compares GC to "ideal" manual memory management, ignoring the fact that manual memory management is not free either. Things like heap fragmentation or computational cost of running allocation/deallocation code do exist and may cause also some real problems. The costs lie elsewhere, but that doesn't mean they don't exist. My experience with large applications is completely different than the conclusion of the paper. Unless you're doing something completely crazy like generating several GBs of garbage per second, modern generational GCs overhead is typically very small (<5%) with only 20-50% more memory than the live set size, not 3-5x as the paper claims. The biggest pain not solved completely are pauses, but researchers are actively working on it and things are getting much better.
- pcwalton 13y ago
- awj 13y agoI'm not sure how you can achieve low level performance and memory safety without dealing with this sort of thing.
- pohl 13y ago2014 AD For comparison, shared_ptr didn't appear in C++ until C++11, which was approved a mere 998 days ago.
- steveklabnik 13y ago`shared_ptr` is really closer to `Rc<T>` (the old `@`pointers). `&` in Rust is more like `const&` in C++, with some extra immutability.
- pohl 13y agoWould auto_ptr/unique_ptr have been a better comparison?
- steveklabnik 13y ago`unique_ptr` is like `Box<T>` (the old `~`).
- pohl 13y agoWell this is all very humbling. I'm a mostly "managed language" weenie at the moment, but I swear I've read the phrase "ownership semantics" in reference to something in this neck of the C++ woods. Rust is shaping up to pass the Alan Perlis test quite handily as a language worth studying.
- steveklabnik 13y agoNo worries. :) Yes, see, in C++, you still need to think about ownership, the compiler just can't help you out. One way of thinking about Rust is "C++, but the compiler understands ownership and memory lifetime." https://github.com/mozilla/rust/wiki/Rust-for-CXX-programmers https://github.com/mozilla/rust/wiki/Rust-for-CXX-programmer... is a bit outdated, but you may enjoy giving it a glance.
- DanWaterworth 13y ago
- jganetsk 13y agoOn the contrary, it's about time mainstream languages have started implementing linear type systems. http://en.wikipedia.org/wiki/Substructural_type_system#Linear_type_systems http://en.wikipedia.org/wiki/Substructural_type_system#Linea...
- Kutta 13y agoI totally disagree; Rust is shaping up to be the best alternative to C++ by far. As for being 2014, I'd argue that linear and substructural typing is pretty much in the cutting edge of language research.
- eq- 13y agoI wonder if there's a (simple syntactical) way to unlink the constness of unique pointers and their targets. It's not a huge obstruction, but seems like an unnecessary restriction not found in the near-equivalent C++ construction.
- steveklabnik 13y agoI'm not sure what you mean about unique pointers and const-ness. Can you explain? You can make unique pointers mutable: fn main() { let mut x = ~5; *x = *x + 1; println!("{:d}", *x); } Or did you mean something else?
- ndeine 13y agoHe means immutability when he says "const-ness". There are four possibilities for mutability of a single pointer: 1. The pointer is mutable, but its contents are immutable. 2. The pointer is immutable, but its contents are mutable. 3. The pointer is immutable and the contents are immutable. 4. The pointer is mutable and its contents are mutable. Right now for owned pointers Rust gives us (3) and (4), but no obvious way to achieve (1) and (2). Although you might argue that the borrowing semantics give us these powers, just not directly with owned pointers - which we shouldn't be using directly if we're asking for that control, we should be lending them out in a well-controlled manner.
- steveklabnik 13y agoAhh, thank you. And yes, that's what I'd argue.
- pcwalton 13y agoYou can use privacy for (1); admittedly it's a little hokey, but I feel it's not worth the added complexity to add field-level immutability directly into the language since you can use other language features to effectively achieve it. `std::cell::Cell` and `std::cell::RefCell` give you (2).