Hacker News new | past | comments | ask | show | jobs | submit login

Generally data lifetime in rust is fully deterministic and the borrow checker can statically determine when data should be deallocated. If for whatever reason you do need reference counted semantics there are options in the stdlib (alloc::rc).



And to elaborate on this, there's a namespace clash: Arc in Rust is _atomic_ reference counting, and Swift is _automatic_ reference counting, which, even more confusingly, is implemented using atomic reference counting in my understanding.

Automatic reference counting inserts all of the refcount bumps. In Rust, you have to write the up count yourself, but not the downcount.

But, reference counting isn't used very often, at least in my experience. It's very useful when you have non-scoped threads, though.


As far as I can tell, the impl of Arc and ARC are actually basically identical at the high level, with the only major diff being ARC only keeps 32-bit counts on 64-bit (so they only waste one pointer of space).

Everything else is just where retain/release (clone/drop) calls are made. Rust is insanely good at not frobbing counts because you can safely take internal pointers and move pointers into a function without touching the counts at all. Swift has lots of interesting optimizations to avoid touching the counts, but it's hard to compete with a system that has so much great static information related to liveness of pointers and values.

As a simple example, consider this code (which is conveniently valid Swift and Rust, modulo snake_vsCamel):

    let x = make_refcounted_thing();
    foo(x);
This code in isolation will always not frob counts for Rust. This code may not frob counts in Swift, depending on what follows `foo`. In particular if foo is in tail position (or at least tail-position-for-the-life-of-x), then we can avoid frobbing, because we know foo's final operations will be to release its function args. foo may in turn punt releasing its function args to anyone it passes them to as a tail call. Note that Swift and Rust both have the usual caveats that "less is a tail call than you think" thanks to side-effecting destructors.

The takeaway is that Rust's default semantics encourage releasing your memory earlier, which in turn means less traffic on the reference counts. Particularly interesting is that in Rust, you can run a function arg's destructor earlier than the end of the function by moving it in to a local variable. In Swift, I do not think this is possible (but I wouldn't be too surprised to be wrong -- Swift has tons of special attributes for these little things).




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: