•  TehPers   ( @TehPers@beehaw.org ) 
    link
    fedilink
    English
    2
    edit-2
    1 year ago

    Lets say we have a spaceship game.

    Some facts about our game’s code:

    • All of our spaceships live in a central list.
    • We also need to have a separate cache for displaying them.
    • Every ship needs to be in both the central list and the display cache.
    • When the ship dies, we need to remove it from both the central list and the display cache.

    If we forget to remove it from the display cache, we’d get an odd bug when displaying.

    Let’s use single ownership to prevent this bug at compile-time. No mainstream language prevents this kind of bug, but we’re about to do it easily!

    The idea of using single-ownership to track “reminder” objects is actually really cool, and a variation of it sees use in other languages too. Traditionally, RAII is used for resource acquisition and freeing (as the name implies) in the context of heap-allocated pointers, so smart pointers for example. However, it can also be used for things like mutexes to automatically free up a mutex when some kind of “guard” object is dropped (both Rust and C++ support this, and Rust even enforces it). It’s not the same as a “reminder” object, but instead of having the compiler tell you “you forgot to free the mutex”, you instead automatically get the mutex freed so you don’t need to explicitly do it anymore.

    The article would be right that languages don’t traditionally enable some kind of “reminder” object in the sense that you can’t compile the code without first doing X with that object. However, from my experience, the RAII approach means you don’t need those reminder objects anyway since the action that you’re supposed to take when you’re done with some resource can be done automatically in these languages.

    Here’s an example in Rust translating the ship/display cache example in the article to something that takes advantage of these “guards” to automatically notify the display cache when the ship is dropped. You’ll notice that in the main function, nowhere do I need to explicitly tell the display cache “hey this ship was destroyed”. Instead, the cache automatically knows and updates its state when the ships() method is called to get the list of ships in the cache. I believe something similar to this can be done in C++. C# would allow you to use IDisposable and .Dispose() to achieve something similar too, although it wouldn’t be an automatic process like in Rust and C++.