miniextendr supports five R class systems. Switch between them with a single attribute change.

🔗Quick Comparison

FeatureEnvR6S3S4S7
Attribute#[miniextendr]#[miniextendr(r6)]#[miniextendr(s3)]#[miniextendr(s4)]#[miniextendr(s7)]
Method Callobj$method()obj$method()generic(obj)generic(obj)generic(obj)
EncapsulationWeakStrongNoneModerateStrong
DependenciesNoneR6 packageNonemethods packageS7 package
Active BindingsNoYesNoNoYes
InheritanceNoLimitedS3 dispatchS4 dispatchS7 dispatch
Best ForSimple APIsComplex stateTidyverse compatBioconductorModern OOP

🔗Choosing a Class System

  • Simple internal API? Use Env (default) – no dependencies, $ dispatch
  • Complex stateful objects? Use R6 – active bindings, encapsulation
  • Tidyverse / generic functions? Use S3 – print.MyClass, format.MyClass
  • Bioconductor ecosystem? Use S4 – formal classes, multiple dispatch
  • Modern R OOP? Use S7 – best of S3 + S4, computed properties

🔗Environment Style (Default)

#[derive(miniextendr_api::ExternalPtr)]
pub struct Counter { value: i32 }

#[miniextendr]
impl Counter {
    pub fn new(initial: i32) -> Self {
        Counter { value: initial }
    }

    pub fn value(&self) -> i32 { self.value }

    pub fn increment(&mut self) { self.value += 1; }
}
c <- Counter$new(0L)
c$value()      # 0
c$increment()
c$value()      # 1

🔗R6 Style

#[miniextendr(r6)]
impl Counter {
    pub fn new(initial: i32) -> Self {
        Counter { value: initial }
    }

    pub fn value(&self) -> i32 { self.value }

    // Active binding (property-like access)
    #[miniextendr(r6(active))]
    pub fn current(&self) -> i32 { self.value }
}
c <- Counter$new(0L)
c$value()    # Method call
c$current    # Active binding (no parens)

🔗S3 Style

#[miniextendr(s3)]
impl Counter {
    pub fn new(initial: i32) -> Self {
        Counter { value: initial }
    }

    pub fn value(&self) -> i32 { self.value }
}
c <- new_Counter(0L)
value(c)     # S3 generic dispatch
print(c)     # Uses print.Counter if defined

🔗S4 Style

#[miniextendr(s4)]
impl Counter {
    pub fn new(initial: i32) -> Self {
        Counter { value: initial }
    }

    pub fn value(&self) -> i32 { self.value }
}

🔗S7 Style

#[miniextendr(s7)]
impl Counter {
    pub fn new(initial: i32) -> Self {
        Counter { value: initial }
    }

    pub fn value(&self) -> i32 { self.value }
}

🔗Trait Methods

Trait implementations can be exposed to R as method groups:

trait Describable {
    fn describe(&self) -> String;
}

#[miniextendr]
impl Describable for Counter {
    fn describe(&self) -> String {
        format!("Counter({})", self.value)
    }
}

In R, trait methods are accessible via Type$Trait$method(obj) (standalone) or obj$Trait$method() ($ dispatch).