4 ms·
Possibly a stupid question, but is this a bit like reference counting, like you see in python, only done at compile time?
by Twirrim 9y ago
Possibly a stupid question, but is this a bit like reference counting, like you see in python, only done at compile time?
- mathw 9y agoNot really. Rust has an idea of "borrowing" references to things, which could be seen as increasing the reference count, but it's not a particularly good analogy because borrows actually have no effect on the original lifetime. So, if you borrow something and try to store it somewhere with a lifetime the compiler thinks is going to outlive the lifetime of the thing you borrowed, that's a compiler error, whereas in a reference counted language or a GCed language the original entity just keeps existing for as long as required. This is usually because said entity is on the heap - Rust puts everything on the stack by default. You can of course put things on the heap, and there is a selection of types available in the standard library which are I guess a bit like C++ smart pointers that let you have heap allocation, reference-counted semantics etc. if you want it.
- rtpg 9y agoIn python you can't really statically define a reference count a = {} b = {} l = [] for _ in range(100): if input('thingy'): l.append(a) else: l.append(b) In that snippet it's impossible to know how many references there are to a or b. In Rust, lifetime management is set up so that your code can statically determine when something no longer can be referred to (hence "free GC"). For example: def f(): a = 3 g(a) # a is no longer used from this point return 5 you can clearly define when things are no longer usable, hence free-able. Python in this context will also free at the end of the function, but it's because it will be decrementing the reference counter and it gets to 0. But Rust won't need to have the reference counter since it knows it can free the object at any point after g. (This isn't a great example for a lot of reasons, Rust allows you to go much further than this) This ends up being somewhat similar to writing code in more statically typed languages/languages with dependent types. You might have to rework your code so that the machine can properly identify when it can free memory.
- nerdponx 9y agoHow then does Rust avoid the if('thingy') issue? Or, for that matter, a language like C, where presumably a and b would be allocated on the stack. In C would they both hang around until the function returns? Or would I have to copy them into the array anyway, which would be heap-allocated?
- steveklabnik 9y agoThey're stack allocated in Rust too, so they're both going to stick around. Arrays in Rust are stack allocated, but this code would probably use a vector, which is heap allocated, and so yeah, you'd end up copying them from the stack to the heap.
- masklinn 9y agoIt's more like compile-time weakrefs, where the compiler ensures that you can't access a weakref after the source strong reference is gone (not just that deref'ing the weakref returns None)
- twic 9y agoA bit. Not completely, but a bit. That analogy may well help you understand how lifetimes work, but it will break down well before you have a workable understanding of lifetimes.
- steveklabnik 9y agoNot a stupid question, as it's a very common way for some people to think about it. I don't think it's very accurate though, and leads to incorrect intuitions. This is because reference counting is prescriptive, that is, the count determines how long a value stays alive. Lifetimes are descriptive, that is, you cannot magically make something live longer by taking an additional reference to it, instead, you'll get an error.
- staticassertion 9y agoNot stupid at all, and something that a lot of people ask. It's not really like that - with reference counting you sort of have multiple 'owners' of a variable, and they all get to 'free' that memory except that 'free' just decrements a counter. With rust there is a very clear owner at all points - you always know that your code in one spot owns the memory, and no other code does. There may be references handed out but those are very clearly distinct - that is, by looking at the code you can see "yes, I own this" or "yes, I'm borrowing this". Now, with borrowing it's a little bit more like reference counting, but it's really just scope based. We know that the references are valid for some scope, and after that scope they are not. There's no internal counting or anything like that in the compiler as far as I am aware.