Build
Private generics

Private Generics

The #[private_generics(T)] function annotation ensures that functions annotated with it can only be called from within the module where T is defined. This annotation provides similar constraints to Move's storage instructions, but it grants this capability to developers.

This annotation is particularly useful for developing foundational contract libraries. It ensures that functions with this annotation cannot be called arbitrarily by users and can only be called through higher-level contract functions.

Let's take Account as an example. We want to store a user's resources within their storage space, but at the same time, we want to restrict a contract to only operate on the resource types it defines and prevent it from operating on resource types defined by other contracts. This is where the #[private_generics(T)] annotation comes into play.

module moveos_std::account{
    #[private_generics(T)]
   /// Borrow a mut resource from the account's storage
   /// This function equates to `borrow_global_mut<T>(address)` instruction in Move
   public fun borrow_mut_resource<T: key>(account: address): &mut T;
}

In the above example, we define a borrow_mut_resource function with a private generic T which can only be used within the module where T is defined. Other modules cannot use this type.

How it works

#[private_generics(T)] is implemented based on Move's verifier, which checks the validity of function calls at compile-time. If an incorrect call is detected, it will result in an error. Additionally, the validity of function calls is checked during contract deployment.

💡

TODO: This part of the document needs improvement.

References

  1. The #[private_generics(T)] annotation is used in the following modules, which can serve as references:
  2. Understanding Private Generics Functions in one article