6 ms·
> Correct... I'm a Pascal programmer. I create objects when a program starts, delete them at the end. Then I guess you should instead say you’re a ‘single-shot
by pwdisswordfish4 6y ago
> Correct... I'm a Pascal programmer. I create objects when a program starts, delete them at the end.
Then I guess you should instead say you’re a ‘single-shot, compiler-like batch job executable’ programmer. I imagine that colours your perception more than the choice of programming language itself. If you were to write a program that has to manipulate deeply nested data structures, or a long-running service that has to acquire and dispose of an unbounded number of various kinds of resources over the course of its runtime in a deterministic manner, you’d start longing for an ownership system very quickly.
- mikewarot 6y agoI'm trying to imagine when I'd worry about ownership. The only thing that comes to mind for me is having to provide buffers for string results from OS calls, etc. In Pascal, you can return a string, assign it, append it, etc.. and never have to allocate/dispose of them... its taken care of under the hood by automatic reference counting. I'd really like to understand this... what specific type of thing were you doing when you found yourself longing for an ownership system? [edit] It occurs to me that anytime I have objects, they eventually trace their ownership to a single global variable. Perhaps that has something to do with this?
- steveklabnik 6y agoIt is an alternative, in many cases, to automatic reference counting. It's sort of like saying "why would I need automatic reference counting? I have a tracing garbage collector."
- mikewarot 6y agoThat makes sense... thanks! So, in general, if something is too big to fit to easily be copied, or stored in a single variable of known size (like strings, dictionaries, lists, trees, etc.) its either GC or ARC to the rescue?
- steveklabnik 6y agoNo problem. :) That's not quite it. It's more about compile time vs runtime. Arc and GC are runtime tracking of "when can this be freed." Ownership is compile-time tracking of the same. Rust has refcounted types in its standard library, but you only need to use them relatively rarely. Here's a small example with not too much syntax. The core idea: fn main() { // String is a heap allocated, mutate-able string type let s = String::from("foo"); } // s goes out of scope here, and so will be freed here; // the compiler generates the code to free the heap allocation at this point s is the "owner," and there's only one, so this can be tracked fully at compile time. Onwership can move, too. Let's introduce a function: fn foo(bar: String) { // body would go here, elided to keep this simple } // because bar is of type "String", this function "takes ownership" of the // value passed as 's', and so the compiler will generate the code to free // its heap allocation at this point fn main() { let s = String::from("foo"); // we pass s to foo... foo(s); } // ... and because we did, it no longer exists in main, and the compiler // knows this, so no code to free the allocation is generated here. if // it were, this would lead to use-after-free. All of this is trackable, 100%, at compile time. So there's no runtime overhead here at all. But imagine that foo() creates a new thread inside of it, and we want to access said string from inside that thread, as well as from within main. Now we have multiple owners, not a single one, and it's not possible at compile time to know when the string should be freed. The simplest solution here is to reach for reference counting, and you'd end up with Arc<String>, that is, a String that's wrapped in an atomic reference count. (Also, references don't take ownership, so if you didn't want to have foo free its argument, you'd have it accept a reference, rather than a String directly. This would let you temporarily access the string, without freeing the backing storage when the function's body has run its course.
- mikewarot 6y agoWow... that's quite a bit more than Garbage collection... thanks for explaining it.
- adamnemecek 6y agoThe examples are numerous but for example databases or GUI frameworks. You end up in situations where a parent needs a reference to a child and child needs a reference to its parent and it gets unwieldy.