Generics & Constraints
Type arguments are usually inferred; specify explicitly with new_box<u64>(5) when needed.
19.1 Generic functions and structs
Type arguments are usually inferred; specify explicitly with new_box<u64>(5) when needed.
public struct Box<T> has copy, drop, store { value: T }
public fun new_box<T>(value: T): Box<T> { Box { value } }
public fun unbox<T>(b: Box<T>): T { let Box { value } = b; value }
public struct Pair<A, B> has copy, drop { a: A, b: B }
public fun swap_pair<A, B>(p: Pair<A, B>): Pair<B, A> {
let Pair { a, b } = p;
Pair { a: b, b: a }
}19.2 Ability constraints
Allows inside the function Copy / dereference T Let T go out of scope, overwrite it Put T inside storable structs
Aptos: global storage ops on T; Sui: treat T as an object T: copy + drop + store Combine with +
public fun duplicate<T: copy>(x: &T): (T, T) { (*x, *x) }
public fun discard<T: drop>(_x: T) { }
public fun store_in<T: key + store>(obj: T, to: address) {
transfer::public_transfer(obj, to); // Sui
}
// Aptos: generic resource check
public fun has_resource<T: key>(addr: address): bool { exists<T>(addr) }19.3 Monomorphization and no dynamic dispatch
Generics are type-checked once and instantiated per concrete type at runtime; there are no trait objects or interfaces. A generic function can only do with T what its constraints allow — it cannot inspect fields of T because it does not know them.
19.4 Type reflection helpers
std::type_name::get<T>() (Sui; Aptos has aptos_std::type_info::type_of<T>() and type_name<T>()) returns the fully qualified type name — useful for registries and witnesses.
Sui sui::types::is_one_time_witness(&w) checks the one-time witness property (Chapter 31).