6 ms·
I think that being able to write down the lifetimes in the language is beautiful. You don't have to do it, but if you want to do it, being able to do so in a w
by volta87 6y ago
I think that being able to write down the lifetimes in the language is beautiful.
You don't have to do it, but if you want to do it, being able to do so in a way that's verified and enforced by the toolchain beats doing so in a documentation comment.
Now every time I read a doc string saying that I need to "deepcopy" something in Python for some API usage pattern to work properly I cringe.
- fasterthanlime 6y agoThat's one of the things that get me about Rust discourse: it seems that "Rust is pain in exchange for performance" is a common misconception. Rust is discipline in exchange for performance and correctness. A GC lets you be relatively worry-free as far as memory leaks go (and even then..) but it doesn't prevent a lot of the correctness problems the borrow checker would. With a checker you're forced to think: do I really want to pass a copy/clone of this? Or do I want to let that function borrow it? Or borrow it mutably?
- harikb 6y agoWhile I get the point about data-races, a “GC” doesn’t make/help you leak memory - you have simply postponed the free to a later point in time. Assume you had some code that takes a file name and calls open on it. One day you decide you want to print that filename before you open it. Naive code will cause the name to “move” to print and unusable to the open in next line. Even though it is perfectly understood by all parties that there is no threading involved and print would finish before the next use of that string. Yes, I can create a borrow or clone, but having to think of it every single line of code even when there is only one thread of execution is really painful Edit: I get print is a macro, but imagine a detailed logger for this case.
- fasterthanlime 6y agoI'd argue the exact opposite. Languages that don't have a concept of ownership, and a borrow checker, and don't explicitly say if they want ownership, a reference, or a mutable reference, force you to keep all of these details in your head. Here, if I have a `&T` and I try to call a function that has a `&mut T`, the compiler will tell me that's not gonna work - and then I can pick whether I want my function to take a `&mut T`, or if I want to make a clone and modify that, etc. There's a learning curve, it's a set of habits to adopt, but once you embrace it it's really hard to go back to languages that don't have it! (See the rest of the comments for testimonials)
- millstone 6y agoI think both points are right. There's times when it's useful and desirable to be specific about lifetimes, and there's also times where it's annoying noise. Bignum arithmetic is an example of the latter. You want to just work with numbers, and in Python you can, but in Rust you must clutter your code with lifetimes and borrows and clones. Swift's plan to allow gradual, opt-in lifetime annotations seems really interesting, if it works.
- CDSlice 6y agoBignum arithmetic actually is pretty simple in Rust if you use the right library. Rug[0] makes using bignums look almost just like using native numbers through operator overloading. [0] https://crates.io/crates/rug https://crates.io/crates/rug
- millstone 6y agoThe operator overloading is nice but you still get smacked in the face right away by the borrow checker. Simple stuff like this won't compile ("use of moved value"): let a = Integer::from(10); let b = a + a;
- smmalis37 6y agolet b = &a + &a; will work, but I agree it's unfortunate that this is necessary.
- pimeys 6y agoThis would work if `Integer` would implement the `Copy` trait. But I guess that type is heavy enough for it to be too expensive, therefore forcing you to explicitly call `clone()`.
- Measter 6y agoThat `Integer` type can't implement `Copy` because it manages a resource, meaning you can't just do a simple memcpy of the type.
- yakubin 6y agoI don't see how a GC would do anything with memory leaks. When you have a data structure containing some elements, and you keep a reference to the structure, because you need some data from it, but you let it grow, then you have a leak, GC or no GC. If anything, GC encourages memory leaks by making freeing memory implicit, something a programmer normally doesn't think about. And yet a resize/push operation on a vector (sic!) is just another malloc. One that will get ignored by a GC. GC protects you against double-free and use-after-free, but memory leaks? Nope.
- snewman 6y agoGC also protects you against forget-to-free, which in most non-GC languages is a common form of memory leak.
- yakubin 6y agoThat's just exchanging forget-to-free for forget-to-drop-reference.
- snewman 6y agoBut it's much easier to forget-to-free: Foo* foo = new Foo(); ...code that uses foo... This is a memory leak in a non-GC language, but not in a GC language. In a practical sense... is it your personal experience that memory leaks are equally prevalent in GC and non-GC languages? I've spent decades working in each (primarily C++ and Java, but also Pascal, C, C#, Smalltalk...) and my experience is that memory leaks were a _much_ bigger issue, in practice, in the non-GC languages.
- yakubin 6y agoThis is a memory leak in a GC language as well, depending on what happens to foo in ...code that uses foo... Maybe it will become a field of some class, maybe it will get pushed to some queue, maybe it will get captured in a lambda, etc. You won't even be able to tell just from looking at this code in this one place alone, if you passed this pointer as argument to a function. It is my experience that when people work with GC languages, they treat the GC as a blackbox (which it is) and simply won't bother investigating: do they have memory leaks? Of course not, they are using a GC after all, all memory-related problems solved, right? Right... With code that relies on free(), I can use a debugger and check which free() calls are hit for which pointers. Even better, I may use an arena allocator where appropriate and don't bother with free() at all. With a GC I'm just looking at some vague heap graph. Am I leaking memory? Who knows... "Do those numbers look right to you?" Memory management issues are usually symptoms of architectural issues. A GC won't fix your architecture, but it will make your memory management issues less visible. It is my experience that most memory problems in C come from out-of-bounds writes (which includes a lot more than just array access), not from anything related to free(). A GC doesn't help here.
- yakubin 6y agoFor me it's also faster to read lifetimes, which have a standard concise syntax, versus ad-hoc documentation.