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).