13 ms·
Using automated resource management to drive socket (and handle, in general) lifetime is a terrible idea. Sometimes you really, really want to close a handle at
by kevingadd 12y ago
Using automated resource management to drive socket (and handle, in general) lifetime is a terrible idea. Sometimes you really, really want to close a handle at a given time. The disposal of associated resources is another matter, and automating that is fine, but leaving a socket open 5 seconds too long is simultaneously 'correct' from a garbage collection perspective and totally, totally not the right thing to do.
The key observation here is that things like closing sockets are actual information channels, so tying them to implementation details like object lifetime is a terrible idea. This, concidentally, is why some attempts to tie the lifetime of long-running tasks/threads to object lifetime are a bad idea.
- steveklabnik 12y agoYou can call drop() manually if you want it closed before the end of the scope, no harm, no foul.
- ef4 12y agoThere is no garbage collection in rust. There is no possible "five second gap". Wherever you would have written "socket.close()", in rust you can just say "drop(socket)". The difference is, it takes advantage of the ownership system to statically prove that you won't try to use the socket after close. Or just let it go out scope and it will be dropped immediately. NOT eventually garbage collected.
- monocasa 12y ago> Wherever you would have written "socket.close()", in rust you can just say "drop(socket)". The difference is, it takes advantage of the ownership system to statically prove that you won't try to use the socket after close. Does a drop somehow say something to the type system as well, disallowing reads and writes afterwards? I'm new to rust, sorry if that's a stupid question.
- pcwalton 12y ago> Does a drop somehow say something to the type system as well, disallowing reads and writes afterwards? Yes.
- Leon 12y agoThe other poster says it proves operations won't happen again - does it do both?
- kibwen 12y agoYep! The owner of a thing can do the following: 1. Give ownership away to something else. 2. Free the object at the end of the scope. In order to do anything to the object, you give up ownership to the function that does it (which can then give it back, if it doesn't need ownership of the value any more and doesn't want to free it itself). This even applies to the `drop` function, which just takes ownership and then does nothing whatsoever to the passed-in value, allowing it to go out of scope immediately. So once you've called `drop(foo)`, you no longer own the value and so can't give it away to any reading or writing function, and you can't drop it for the very same reason.
- hrjet 12y agoCurious to know why `drop` isn't called automatically by the compiler as soon as possible (since the type system already seems to know it is safe). Is there a trade-off involved here?
- kibwen 12y agoFreeing resources as soon as humanly (computerly?) possible will optimize your memory usage, but can actually be worse for execution speed. If you're willing to use slightly more memory, it's generally faster to free memory in coarse chunks than one-thing-at-a-time. So even though Rust can conceivably free memory sooner, it might as well defer freeing until the end of the scope, since it can prove that that's safe. To take this to the logical extreme, see this awesome post from Walter Bright, where he doubles the speed of the D compiler by providing a custom malloc implementation that never frees, leaking all memory until the end of the process: http://www.drdobbs.com/cpp/increasing-compiler-speed-by-over-75/240158941 http://www.drdobbs.com/cpp/increasing-compiler-speed-by-over...
- kibwen 12y agoIn fact, the `drop` function is totally trivial. It's just a function that takes ownership of a thing, then does nothing with it whatsoever. In other words, the function body is entirely empty! :) https://github.com/rust-lang/rust/blob/master/src/libcore/mem.rs#L348 https://github.com/rust-lang/rust/blob/master/src/libcore/me...
- portmanteaufu 12y agoHa! I've been using this function for ages and always assumed it was a compiler built-in. I love that it's just that simple.
- Double_Cast 12y agoThat's just too perfect. Of all things, your comment has raised my opinion of Rust the most.
- Leon 12y agoI have not used Rust before; does working with statistical analysis of runtime environments hinder debugging? In a multithreaded environment - does it pause the world for its runtime analysis or are there locks on shared resources representing ownership of individual objects, or does it do copies on writes of resources for idempotent operations as the references are moved around environment for lockless operations?
- steveklabnik 12y ago> does it pause the world for its runtime analysis The borrow checker is _entirely_ at compile time.
- ben0x539 12y agoTo be fair, resource disposal is sometimes "delegated" to runtime. But it's always a local concern, like a reference counter for a shared resource, or a mutable `Option<R>` value that can have the R resource taken out of it or put back into it dynamically. There's no creepy overarching runtime system that tracks individual objects from a distance.
- steveklabnik 12y agoYes, it's hard to figure out which way to talk about it. Rc<T> isn't really part of the borrow checker... it technically subverts it to do its own thing internally.
- ben0x539 12y agoI wouldn't really consider the whole ownership thing or specifically the mechanism that inserts destructor calls at the logical end of a value's lifetime part of the borrow checker either, but I dunno how the implementation is laid out.
- solipsism 12y agoJust to be clear (and to check this myself -- I'm just starting to learn Rust), a five second gap is actually possible right? Say I use a socket, stop using it, don't call drop(socket), and I don't leave the scope for 5 seconds because I'm busy doing something.
- ef4 12y agoYes, you are correct. What I was trying to explain is that the timing is deterministic and immediate. People are used to unpredictable GC and rightly don't want to trust it with thing like this.
- ben0x539 12y agoYeah, if you hold on to the thing in your scope, it won't go out of scope and won't be disposed of.
- tomp 12y agoI agree. Having files and sockets close automatically is a bad pattern. Ideally, in a language with linear types, the compiler would notify you of all resources that you didn't properly dispose of when they go out of scope - so, unless you return the handle or call `close(f)` at the end of the function, you'd get a compiler error. The compiler could also auto-insert `close()`/`dispose()` methods when they go out of scope, as is implemented in Rust using the Drop trait. I don't know if Rust supports forcing explicit deallocation, but even if it doesn't, it's still an improvement compared to most GC-d languages.
- dkhenry 12y agoIf I understand the borrowing and lifetime mechanisms of rust it would be trivial to have it say anything that has a lifetime that is active at the end of a scope is a compiler error. It would almost be like how in c++ you can disable copying by setting all the copy constructors to delete and then the compiler will tell you if your accidentally making copy's of objects.
- tomp 12y agoI agree, it would probably be trivial. It's mostly a language/library design issue, not a type-systems research problem.
- steveklabnik 12y agoYou're talking about linear types, Rust implements affine types. They're very similar.