Giter Club home page Giter Club logo

inherit-methods-macro's Introduction

Inherit methods from a field automatically (via procedural macros).

Motivation

While Rust is partially inspired by the object-oriented programming (OOP) paradigm and has some typical OOP features (like objects, encapsulation, and polymorphism), it is not an OOP language. One piece of evidence is the lack of inheritance, which an important pillar of OOP. But don't take me wrong: this lack of inheritance is actually a good thing since it promotes the practice of composition over inheritance in Rust programs. Despite all the benefits of composition, Rust programmers have to write trivial fowarding methods, which is a tedious task, especially when you have to write many of them.

To address this pain point of using composition in Rust, the crate provides a convenient procedure macro that generates forwarding methods automatically for you. In other words, your structs can now "inherit" methods from their fields, enjoying the best of both worlds: the convenience of inheritance and the flexibility of composition.

Examples

Implementing the new type idiom

Suppose that you want to create a new struct named Stack<T>, which can be implemented by simply wrapping around Vec<T> and exposing only a subset of the APIs of Vec. Here is how this crate can help you do it easily.

 use inherit_methods_macro::inherit_methods;
 pub struct Stack<T>(Vec<T>);

 // Annotate an impl block with #[inherit_methods(from = "...")] to enable automatically
 // inheriting methods from a field, which is specifiedd by the from attribute.
 #[inherit_methods(from = "self.0")]
 impl<T> Stack<T> {
     // Normal methods can be implemented with inherited methods in the same impl block.
     pub fn new() -> Self {
         Self(Vec::new())
     }

     // All methods without code blocks will "inherit" the implementation of Vec by
     // forwarding their method calls to self.0.
     pub fn push(&mut self, value: T);
     pub fn pop(&mut self) -> Option<T>;
     pub fn len(&self) -> usize;
 }

If you want to derive common traits (like AsRef and Deref) for a wrapper type, check out the shrinkwraprs crate.

Emulating the classic OOP inheritance

In many OOP frameworks or applications, it is useful to have a base class from which all objects inherit. In this example, we would like to do the same thing, creating a base class (the Object trait for the interface and the ObjectBase struct for the implementation). that all objects should "inherit".

use std::sync::atomic::{AtomicU64, Ordering};
use std::sync::Mutex;

use inherit_methods_macro::inherit_methods;

pub trait Object {
    fn type_name(&self) -> &'static str;
    fn object_id(&self) -> u64;
    fn name(&self) -> String;
    fn set_name(&self, new_name: String);
}

struct ObjectBase {
    object_id: u64,
    name: Mutex<String>,
}

impl ObjectBase {
    pub fn new() -> Self {
        static NEXT_ID: AtomicU64 = AtomicU64::new(0);
        Self {
            object_id: NEXT_ID.fetch_add(1, Ordering::Relaxed),
            name: Mutex::new(String::new()),
        }
    }

    pub fn object_id(&self) -> u64 {
        self.object_id
    }

    pub fn name(&self) -> String {
        self.name.lock().unwrap().clone()
    }

    pub fn set_name(&self, new_name: String) {
        *self.name.lock().unwrap() = new_name;
    }
}

struct DummyObject {
    base: ObjectBase,
}

impl DummyObject {
    pub fn new() -> Self {
        Self {
            base: ObjectBase::new(),
        }
    }
}

#[inherit_methods(from = "self.base")]
impl Object for DummyObject {
    // Give this method an implementation specific to this type
    fn type_name(&self) -> &'static str {
        "DummyObject"
    }

    // Inherit methods from the base class
    fn object_id(&self) -> u64;
    fn name(&self) -> String;
    fn set_name(&self, new_name: String);
}

inherit-methods-macro's People

Contributors

stevenjiang1110 avatar

Watchers

 avatar  avatar  avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.