[HN Gopher] Show HN: How to program in Rust as if it was old sch...
       ___________________________________________________________________
        
       Show HN: How to program in Rust as if it was old school C++ with
       pointers
        
       Basically wrap your data struct in Option<Rc<RefCell<_>>>  Better
       yet, use your custom type that provides few helper functions that
       make using it as nice as old C++ pointers.  Obviously there's no
       pointer arithmetic, but it works great for dynamically allocated
       structures like trees or linked lists.  Please comment how it's a
       horrible idea that will bring doom to me and my family.
       fn main() {             struct Data { pub number: i32 }
       // struct Data { int number; };                          let mut
       p:Pointer<Data> = Pointer(None);    // Data *p = NULL;
       println!("{}", p.is_none());                // printf(p == NULL ?
       "true\n" : "false\n");                          p =
       Pointer::new(Data { number: 5 });       // p = new Data { number: 5
       };             println!("{}", p.pointed().number);         //
       printf("%d\n", p->number);                          let q =
       p.clone();                          // auto q = p;
       q.pointed().number = 6;                     // q->number = 6;
       println!("{}", p.pointed().number);         // printf("%d\n",
       p->number);                      println!("{}", p.is_clone_of(&q));
       // printf(p == q ? "true\n" : "false\n");         }
       // delete p;       Helper Pointer<T> type:                   use
       std::{rc::Rc, cell::{RefCell, RefMut}};
       #[derive(Debug)]         struct Pointer<T>(Option<Rc<RefCell<T>>>);
       impl<T> Clone for Pointer<T> {             fn clone(&self) -> Self
       {                 Pointer(Some(self.0.as_ref().unwrap().clone()))
       }         }                  impl<T> Pointer<T> {             pub
       fn new(d: T) -> Pointer<T> {
       Pointer(Some(Rc::new(RefCell::new(d))))             }
       pub fn pointed(&self) -> RefMut<T> {                 let res =
       self.0.as_ref().unwrap().as_ref().borrow_mut();                 res
       }             pub fn is_clone_of(&self, other:&Pointer<T>) -> bool
       {                 Rc::ptr_eq(&self.0.as_ref().unwrap(),
       &other.0.as_ref().unwrap())             }             pub fn
       is_none(&self) -> bool {                 self.0.is_none()
       }         }            Live version (Rust):  https://play.rust-
       lang.org/?gist=f43ce73b89537e0a9ae0586169b...  Live version (C++):
       http://tpcg.io/_LNG59M
        
       Author : scotty79
       Score  : 14 points
       Date   : 2022-12-20 16:13 UTC (6 hours ago)
        
       | scotty79 wrote:
       | Whats most impressive for me is that making completely safe,
       | effortlessly mutable and flexible linked list in Rust (or any
       | other similar structure) can be as simple as:
       | struct LinkedListNode {           data: i32,           next:
       | Pointer<LinkedListNode>         }
       | 
       | You still need to care about memory leaks through structs linking
       | to each other though because Rc means "reference counted".
        
       | sph wrote:
       | Option<Rc<RefCell<_>>> is not the same thing as a pointer, as the
       | semantics are different, and it uses much more memory than an
       | actual pointer.
       | 
       | Rust has pointers. If you want to program like old school C++,
       | wrap everything in unsafe and use all the pointers you want.
        
         | scotty79 wrote:
         | I don't want unsafe. I just want it to be out of my hair.
         | RefCell is perfectly safe.
        
       | itishappy wrote:
       | C++ compiles down to 90 lines of ASM.
       | 
       | https://godbolt.org/z/YYaK8f9rz
       | 
       | Rust compiles down (up?) to 1428!
       | 
       | https://godbolt.org/z/91YfzT5fb
       | 
       | Thanks, I hate it! Do dynamic typing next!
        
         | worldsavior wrote:
         | It's because of the libraries. They get compiled once.
        
           | steveklabnik wrote:
           | It's because they don't have the same semantics, you are
           | adding overhead with the Rust version in multiple ways.
        
             | scotty79 wrote:
             | I wonder how much difference there would be if I used
             | shared_ptr in C++ instead of the bare one.
             | 
             | EDIT:
             | 
             | As far as I can tell less than 190 lines of asm but I don't
             | know shared_ptr enough to produce exactly the same code.
        
               | steveklabnik wrote:
               | Yeah, that gets closer for sure. refcell is still going
               | to add a bit of state to the value inside of the
               | allocation, but at least the shared_ptr and Rc/Arc bits
               | are the same semantic, so it'll be closer!
        
         | scotty79 wrote:
         | For that small price you get security against everything except
         | memory leaks (which you don't get anyways in this bare C++
         | either) not to mention other Rust niceties while keeping
         | superficially same convenient semantics.
        
         | [deleted]
        
       | gavinray wrote:
       | How is this any different than using a mutable reference or
       | pointer to the "T"?                 struct Pointer<T> { ptr: *mut
       | T }       struct Pointer<T> { ptr: &mut T }
       | 
       | This is just adding a ton of overhead and memory usage
        
         | scotty79 wrote:
         | You can safely pass Rc<RefCell<_>> around your program and
         | store inside any structures without pretty much any concern for
         | any lifetimes.
        
       ___________________________________________________________________
       (page generated 2022-12-20 23:02 UTC)