Hacker News new | ask | show | jobs
by pjmlp 1831 days ago
You aren't reading it properly, the documentation you are reading is for the case you leave the work to the GC, you can take it yourself C++ RAII style:

   {
      using my_socket = new NetworkSocket()

   }

   // my_socket no longer exists when code arrives here

Or even better if NetworkSocket is a struct, it gets stack allocated, zero GC.
2 comments

So how about this then:

    {
      using my_socket = new NetworkSocket();
      my_socket.write("Started");
      register_callback(() => my_socket.write("Finished"));
    }
This is the case what RC solves well and tracing GC doesn't solve at all, regardless of the number of interfaces you implement. It is easy to find yourself in this situation given how much callbacks are used in modern codebases.

    NetworkComponent foo = new NetworkComponent();

    {
       using my_socket = new NetworkSocket();
       foo.socket = my_socket;
    }

    foo.do_sth_with_socket(); // oops, runtime failure, socket closed
Trying to be clever?

Here is your Rust version, enjoy.

    use std::io::{self};

    struct NetworkComponent {
      socket : NetworkSocket
    }

    impl NetworkComponent {
        fn new() -> NetworkComponent {
            println!("Creating NetworkComponent");
            NetworkComponent {
                socket : NetworkSocket{}
            }
        }
        
        fn do_sth_with_socket(&self) {
            
        }
    }

    impl Drop for NetworkComponent {
        fn drop(&mut self) {
            println!("Dropping NetworkComponent");
        }
    }    


    struct NetworkSocket {
        
    }

    impl Drop for NetworkSocket {
        fn drop(&mut self) {
            println!("Dropping NetworkSocket");
        }
    }  

    fn main() -> io::Result<()> {
        let mut foo = NetworkComponent::new();
        
        {
            let socket = NetworkSocket{};
            foo.socket = socket;
        }
        
        foo.do_sth_with_socket(); // oops, runtime failure, socket closed
        
        Ok(())
    }
https://play.rust-lang.org/?version=stable&mode=debug&editio...
And what did you try to prove here? There is no use after free and no runtime error in this rust code. The socket stays valid since the moment of its creation and for the whole lifetime of the network component. It gets moved out of nested scope properly and gets closed after leaving the outer scope, after dropping the NetworkComponent struct.

The "oops" comment is invalid in your Rust example because the socket is still valid at that point.

Which is totally different than what would happen in C#, where you'd get use-after-free bug (actually use-after-close).

Try with resources is not RAII. It is a lot weaker.

> foo.do_sth_with_socket(); // oops, runtime failure, socket closed

Happens just as well in Rust, why do you think I gave you a Playground link.

If you want, I can shut up the cleverness with a cargo build example instead of a dummy playground example.

The playground link confirms the socket is closed after dropping networkComponent.

Last two lines of the output:

    Dropping NetworkComponent
    Dropping NetworkSocket
Btw: you probably fooled yourself by accidentally creating 2 sockets, and indeed the first one gets dropped immediately when you lose (overwrite) the reference to it. Use Option to avoid that.
You forgot another line, it was actually:

    Creating NetworkComponent
    Dropping NetworkSocket
    Dropping NetworkComponent
    Dropping NetworkSocket
Besides, you forgot another tiny detail,

By replacing the socket now the port number is another one, and all processes that had open connections to that port will now crash, or have messages dropped without getting why.

I can also fabricate plenty of error situations with Rust if you feel so inclined.

And if you were actually serious, you would be aware that there are Roslyn analysers that validate IDispose follows proper RAII patterns, like https://github.com/DotNetAnalyzers/IDisposableAnalyzers

Remember, Rust isn't perfect, and only fixes 70% of existing error patterns, I can have plenty of inspiration with the remaining 30%.