This presentation by Michael Lawrence introduces S7, a new object-oriented (OO) programming system for the R language, developed through a collaboration between Posit and the R Consortium. The talk outlines the philosophy behind S7, which aims to provide a modern, robust, and more intuitive alternative to R's existing S3 and S4 systems. Lawrence details the shortcomings of S4, including its complex multiple dispatch mechanism, incompatibility with S3, and the tendency to expose internal implementation details ("slots"), which breaks abstraction.
S7 is presented as a solution that is more idiomatic to R. Its core features include treating classes and generics as first-class objects, ensuring full S3 compatibility, and introducing encapsulated "properties" that can be dynamic and validated. A key design decision in S7 is the enforcement of single inheritance. The speaker uses the rectangular_data class from Bioconductor as a case study to argue that this constraint encourages better software design by favoring composition over inheritance for sharing behavior, leading to clearer and more maintainable code. The presentation concludes with practical examples of S7 syntax for defining classes, properties, and methods.
An Introduction to the S7 Object-Oriented System for R
0:00:04Overview and Goal: The speaker introduces S7, a new object-oriented system for R developed as a collaboration between Posit and the R Consortium. The goal is to address issues with the S3 and S4 systems, with a particular focus on the challenges of multiple versus single inheritance in the context of porting Bioconductor packages.
0:01:41Core Philosophy of R and OO: R is framed as an extensible, function-oriented user interface where object orientation is key. The concept of polymorphism (a function behaving differently based on object type) and dynamic dispatch is central to R's design.
0:09:56Governance of Generics: An aside discusses the challenge of managing generic function names across different R ecosystems (e.g., tidyverse vs. Bioconductor). S7 does not solve this "governance" issue, which remains a matter of community negotiation.
0:15:18Key Problems with the S4 System: The talk identifies several drawbacks of S4 that S7 aims to fix:
S4 objects are not fully compatible with S3 objects.
It relies on side effects (registering classes and methods in global tables) rather than treating them as first-class R objects.
It exposes internal data structures ("slots"), which violates encapsulation and makes code brittle.
Its multiple dispatch mechanism is complex and hard to reason about.
0:22:36S7's Modern Approach: S7 introduces a more intuitive syntax where classes, generics, and properties are first-class R objects. This avoids side effects and integrates cleanly with R's existing namespace and object-handling mechanisms.
0:28:40Encapsulated and Dynamic Properties: Instead of slots, S7 uses "properties." These are objects themselves that can have getters, setters, and validators. This allows for creating "dynamic" properties that are computed on-the-fly and ensures a clean separation between an object's public interface and its internal implementation.
0:32:56Simplified Hierarchical Dispatch: S7 replaces S4's complex distance-based multiple dispatch with a simpler, predictable hierarchical dispatch. It resolves methods by considering arguments sequentially, which eliminates ambiguity and is easier for developers to understand.
0:36:54The Single Inheritance Decision: A major design choice in S7 is to only allow single inheritance. The speaker uses Bioconductor's rectangular_data virtual class, which uses multiple inheritance in S4, as a case study.
0:38:01Promoting Composition Over Inheritance: The speaker argues that many use cases for multiple inheritance, like rectangular_data, are better solved with composition. The principle is that an object has a certain capability (e.g., a rectangular shape) rather than being an instance of that capability, a design pattern S7 encourages.
0:41:17Alternative Design Patterns in S7: To achieve the code-sharing goals of multiple inheritance, S7 developers can use shared helper functions or, more robustly, design a common base class (e.g., Collection) and define methods on it that query an object's capabilities (e.g., number of dimensions) to achieve polymorphic behavior.
0:52:08S7 Syntax in Practice: The talk concludes with code examples demonstrating how to define classes with inheritance (parent = ...), create reusable properties with defaults and validation, define class unions with the | operator, and implement methods for S7 and S3 generics.