implementing OOP in rust

skywxp發表於2024-04-11

Hi, this is the fifth blog of rust, I will talk about implementing OOP in rust. I have learned some some other OOP languages like Java, and I really like the OOP pattern of programming. In this blog, we will try to implement OOP with rust.

In the OOP, we will usually store the data in to a object. In Java, we will use class:

public class Puppy{
   int puppyAge;
   
}

And, we need some constructor to build the class into an object.

Also , we can add some method into this object, If we want to use these method, we need to ‘new’ the object, and take use of these method with the new object.

public class Puppy{
   int puppyAge;
   public Puppy(String name){
     
      System.out.println("name : " + name ); 
   }
 
   public void setAge( int age ){
       puppyAge = age;
   }
 
   public int getAge( ){
       
       return puppyAge;
   }
 
   public static void main(String[] args){
  
      Puppy myPuppy = new Puppy( "tommy" );
     
      myPuppy.setAge( 2 );
      
      myPuppy.getAge( );
      
     
   }
}

Ok, these are some simples in java, then, how can we do this in rust?

Let’s try it, we know that the struct in rust can store different kinds of data, this is similar to class in rust, and impl key word can give methods to the struct, this is quite similar to the declaration of the method for class in java! Let’s have a try!

Emmmmm, we might lost something, in java, there is a key word new to create a object with the class, but in rust, we do not have it. We need to add a new fn named new for creating the obeject.

Ok, everything good. We can see that the difference to java is that it doesn’t provide the key word ‘new’ for us to create a new project, and we need to do it by ourself, and inside the new fn, we have just created a new struct, this can be called a object now: because it has its own method and property, everything goes well!

Now, let’s use the object!

Import the Blog struct into the main function and we can use it directly.

Here is the result:

Ok, everything good.
But, a new question comes to me: in java, we have JVM to manage these object’s lifecycle, which is mentioned in my first blog, rust will take use of ownership system to manage the life of the struct (object here). This seems to be a little creative! I have just learned OOP languages with GC, and I haven’t learned this before, so I come to search some information about this.

After some search, I just come to know that, the basic management of the struct is still based on the borrow, lifecycle and ownership system, this is quite different to java, and this also makes OOP in rust more efficient, without GC, the program will be able to run faster.

Then, we all know that the three main idea of OOP: encapsulation inheritance polymorphism.

Encapsulation is implemented by the struct, this is easy to understand. We put the property into the struct and only provide public method for accessing these data. This can done easily with the help of the struct and impl in rust.

Inheritance is not directly provided in rust. In java, we can use key word extend to extend property for one object from other object.

public class Animal { 
    private String name;  
    private int id; 
    public Animal(String myName, int myid) { 
        name = myName; 
        id = myid;
    } 
    public void eat(){ 
        System.out.println(name+"eating"); 
  }
public class Penguin extends Animal { 
    public Penguin(String myName, int myid) { 
        super(myName, myid); 
    } 
}

But, in rust, we can only do this with the help of trait: If we want to have the same property, just implement this trait.

We can also take use of composition in rust to implement the extend, but I feel that this is a little bit redundant. We need to write more struct to implement the final struct in our mind. Code here:

struct Engine {
    horsepower: u32,
    fuel_type: String,
}

impl Engine {
    fn start(&self) {
        println!("Engine with {} HP started, running on {}.", self.horsepower, self.fuel_type);
    }
}

struct Wheels {
    count: u8,
    type_: String,
}

impl Wheels {
    fn rotate(&self) {
        println!("The {} wheels are spinning.", self.count);
    }
}


struct Car {
    name: String,
    engine: Engine,
    wheels: Wheels,
}

impl Car {
    fn new(name: String, horsepower: u32, fuel_type: String, wheel_count: u8, wheel_type: String) -> Car {
        Car {
            name,
            engine: Engine {
                horsepower,
                fuel_type,
            },
            wheels: Wheels {
                count: wheel_count,
                type_: wheel_type,
            },
        }
    }

    fn start(&self) {
        println!("{} is starting!", self.name);
        self.engine.start();
        self.wheels.rotate();
    }
}

fn main() {
    let my_car = Car::new(String::from("Rusty"), 200, String::from("Petrol"), 4, String::from("Alloy"));
    my_car.start();
}

For polymorphism, this is mentioned in the lecture, the trait is very powerful in this aspect.

The characteristics of rust OOP above just makes me feel that rust is trying to support OOP in its own basic system, which is really novel. Especially for the extend in rust, it has taken a new method to support the extend in OOP. This just makes it really amazing and make me think that: wow, OOP can be done in this way!