r-oop
R言語でオブジェクト指向プログラミングを行う際に、S7、S3、S4、vctrsといった様々なシステムから最適なものを選択し、効率的なクラス設計を支援するSkill。
📜 元の英語説明(参考)
R object-oriented programming guide for S7, S3, S4, and vctrs. Use when designing R classes or choosing an OOP system.
🇯🇵 日本人クリエイター向け解説
R言語でオブジェクト指向プログラミングを行う際に、S7、S3、S4、vctrsといった様々なシステムから最適なものを選択し、効率的なクラス設計を支援するSkill。
※ jpskill.com 編集部が日本のビジネス現場向けに補足した解説です。Skill本体の挙動とは独立した参考情報です。
下記のコマンドをコピーしてターミナル(Mac/Linux)または PowerShell(Windows)に貼り付けてください。 ダウンロード → 解凍 → 配置まで全自動。
mkdir -p ~/.claude/skills && cd ~/.claude/skills && curl -L -o r-oop.zip https://jpskill.com/download/8786.zip && unzip -o r-oop.zip && rm r-oop.zip
$d = "$env:USERPROFILE\.claude\skills"; ni -Force -ItemType Directory $d | Out-Null; iwr https://jpskill.com/download/8786.zip -OutFile "$d\r-oop.zip"; Expand-Archive "$d\r-oop.zip" -DestinationPath $d -Force; ri "$d\r-oop.zip"
完了後、Claude Code を再起動 → 普通に「動画プロンプト作って」のように話しかけるだけで自動発動します。
💾 手動でダウンロードしたい(コマンドが難しい人向け)
- 1. 下の青いボタンを押して
r-oop.zipをダウンロード - 2. ZIPファイルをダブルクリックで解凍 →
r-oopフォルダができる - 3. そのフォルダを
C:\Users\あなたの名前\.claude\skills\(Win)または~/.claude/skills/(Mac)へ移動 - 4. Claude Code を再起動
⚠️ ダウンロード・利用は自己責任でお願いします。当サイトは内容・動作・安全性について責任を負いません。
🎯 このSkillでできること
下記の説明文を読むと、このSkillがあなたに何をしてくれるかが分かります。Claudeにこの分野の依頼をすると、自動で発動します。
📦 インストール方法 (3ステップ)
- 1. 上の「ダウンロード」ボタンを押して .skill ファイルを取得
- 2. ファイル名の拡張子を .skill から .zip に変えて展開(macは自動展開可)
- 3. 展開してできたフォルダを、ホームフォルダの
.claude/skills/に置く- · macOS / Linux:
~/.claude/skills/ - · Windows:
%USERPROFILE%\.claude\skills\
- · macOS / Linux:
Claude Code を再起動すれば完了。「このSkillを使って…」と話しかけなくても、関連する依頼で自動的に呼び出されます。
詳しい使い方ガイドを見る →- 最終更新
- 2026-05-18
- 取得日時
- 2026-05-18
- 同梱ファイル
- 1
📖 Skill本文(日本語訳)
※ 原文(英語/中国語)を Gemini で日本語化したものです。Claude 自身は原文を読みます。誤訳がある場合は原文をご確認ください。
R オブジェクト指向プログラミング
S7, S3, S4, および vctrs: ニーズに合った適切な OOP システムの選択
S7: 新規プロジェクト向けの最新 OOP
- S7 は S3 のシンプルさと S4 の構造を兼ね備えています
- 自動検証による正式なクラス定義
- 既存の S3 コードとの互換性
# S7 クラス定義
Range <- new_class("Range",
properties = list(
start = class_double,
end = class_double
),
validator = function(self) {
if (self@end < self@start) {
"@end must be >= @start"
}
}
)
# 使用例 - コンストラクタとプロパティへのアクセス
x <- Range(start = 1, end = 10)
x@start # 1
x@end <- 20 # 自動検証
# メソッド
inside <- new_generic("inside", "x")
method(inside, Range) <- function(x, y) {
y >= x@start & y <= x@end
}
OOP システム決定マトリックス
S7 vs vctrs vs S3/S4 決定木
まずはこちらから: 何を構築していますか?
1. ベクトルに似たオブジェクト (アトミックベクトルと同様に動作するもの)
vctrs は以下の場合に使用します:
- データフレームの統合が必要な場合 (列/行)
- 型安定なベクトル演算が必要な場合
- factor のような、date のような、または numeric のようなクラスを構築する場合
- 一貫した強制型変換/キャスティングの動作が必要な場合
- 既存の tidyverse インフラストラクチャを使用する場合
例: カスタム date クラス、units、カテゴリデータ
2. 一般的なオブジェクト (複雑なデータ構造、ベクトルに似ていない)
S7 は以下の場合に使用します:
- 正式なクラスが必要な新規プロジェクト
- プロパティの検証と安全なプロパティアクセス (@) が必要な場合
- 複数ディスパッチが必要な場合 (S3 の double dispatch を超える)
- S3 から変換し、より良い構造が必要な場合
- 継承によるクラス階層を構築する場合
- より良いエラーメッセージと発見可能性が必要な場合
S3 は以下の場合に使用します:
- 最小限の構造ニーズを持つシンプルなクラス
- 最大限の互換性と最小限の依存関係
- クイックプロトタイピングまたは内部クラス
- 既存の S3 ベースのエコシステムへの貢献
- パフォーマンスが絶対的に重要な場合 (最小限のオーバーヘッド)
S4 は以下の場合に使用します:
- Bioconductor エコシステムで作業する場合
- 複雑な多重継承が必要な場合 (S7 はこれをサポートしていません)
- うまく機能する既存の S4 コードベース
詳細な S7 vs S3 比較
| 機能 | S3 | S7 | S7 が有利な場合 |
|---|---|---|---|
| クラス定義 | 非公式 (慣例) | 公式 (new_class()) |
保証された構造が必要な場合 |
| プロパティアクセス | $ または attr() (安全でない) |
@ (安全、検証済み) |
プロパティの検証が重要な場合 |
| 検証 | 手動、一貫性がない | 組み込みのバリデーター | データの整合性が重要な場合 |
| メソッドの発見 | メソッドを見つけるのが難しい | 明確なメソッドの出力 | 開発者のエクスペリエンスが重要な場合 |
| 多重ディスパッチ | 限定的 (base generics) | 完全な多重ディスパッチ | 複雑なメソッドディスパッチが必要な場合 |
| 継承 | 非公式、NextMethod() |
明示的な super() |
予測可能な継承が必要な場合 |
| 移行コスト | - | 低い (1〜2時間) | より良い構造が必要な場合 |
| パフォーマンス | 最速 | ~S3 と同じ | パフォーマンスの差はごくわずか |
| 互換性 | 完全な S3 | 完全な S3 + S7 | 古いパターンと新しいパターンの両方が必要な場合 |
実践的なガイドライン
以下の場合、S7 を選択します
# 複雑な検証ニーズ
Range <- new_class("Range",
properties = list(start = class_double, end = class_double),
validator = function(self) {
if (self@end < self@start) "@end must be >= @start"
}
)
# 多重ディスパッチのニーズ
method(generic, list(ClassA, ClassB)) <- function(x, y) ...
# 明確な継承を持つクラス階層
Child <- new_class("Child", parent = Parent)
以下の場合、vctrs を選択します
# データフレーム内のベクトルに似た動作
percent <- new_vctr(0.5, class = "percentage")
data.frame(x = 1:3, pct = percent(c(0.1, 0.2, 0.3))) # シームレスに動作
# 型安定な演算
vec_c(percent(0.1), percent(0.2)) # 予測可能な動作
vec_cast(0.5, percent()) # 明示的で安全なキャスティング
以下の場合、S3 を選択します
# 複雑なニーズのないシンプルなクラス
new_simple <- function(x) structure(x, class = "simple")
print.simple <- function(x, ...) cat("Simple:", x)
# 最大限のパフォーマンスニーズ (まれ)
# 既存の S3 エコシステムへの貢献
S3 パターン
基本的な S3 クラス
# コンストラクタ
new_person <- function(name, age) {
stopifnot(is.character(name), length(name) == 1)
stopifnot(is.numeric(age), length(age) == 1)
structure(
list(name = name, age = age),
class = "person"
)
}
# Print メソッド
print.person <- function(x, ...) {
cat("Person:", x$name, "(age", x$age, ")\n")
invisible(x)
}
# Generic + メソッド
greet <- function(x) UseMethod("greet")
greet.person <- function(x) {
cat("Hello, my name is", x$name, "\n")
}
greet.default <- function(x) {
cat("Hello!\n")
}
S3 継承
# 子クラス
new_employee <- function(name, age, company) {
obj <- new_person(name, age)
obj$company <- company
class(obj) <- c("employee", class(obj))
obj
}
# 継承によるメソッド
print.employee <- function(x, ...) {
NextMethod() # 親の print メソッドを呼び出す
cat("Works at:", x$company, "\n")
invisible(x)
}
S7 パターン
基本的な S7 クラス
library(S7)
# クラスを定義する
Person <- new_class("Person",
properties = list(
name = class_character,
age = class_numeric
),
validator = function(self) {
if (self@age < 0) {
"@age must be non-negative"
}
}
)
# インスタンスを作成する
bob <- Person(name = "Bob", age = 30)
bob@name # "Bob"
bob@age <- 31 # 検証済みの代入
S7 メソッド
# generic を定義する
greet <- new_generic("greet", "x")
# メソッドを追加する
method(greet, Person) <- function(x) {
cat("Hello, my name is", x@name, "\n")
}
# デフォルトメソッド
method(greet, class_any) <- function(x) {
cat("Hello!\n")
}
S7 継承
Employee <- new_class("Employee",
parent = Person,
properties = list(
company = class_character
)
)
# メソッドをオーバーライドする
method(greet, Employee) <- function(x) {
super(x, Person)@greet() # 親メソッドを呼び出す
cat("I work at", x@company, "\n")
}
S7 多重ディスパッチ
# 多重ディスパッチによる generic
combine <- new_ge 📜 原文 SKILL.md(Claudeが読む英語/中国語)を展開
R Object-Oriented Programming
S7, S3, S4, and vctrs: choosing the right OOP system for your needs
S7: Modern OOP for New Projects
- S7 combines S3 simplicity with S4 structure
- Formal class definitions with automatic validation
- Compatible with existing S3 code
# S7 class definition
Range <- new_class("Range",
properties = list(
start = class_double,
end = class_double
),
validator = function(self) {
if (self@end < self@start) {
"@end must be >= @start"
}
}
)
# Usage - constructor and property access
x <- Range(start = 1, end = 10)
x@start # 1
x@end <- 20 # automatic validation
# Methods
inside <- new_generic("inside", "x")
method(inside, Range) <- function(x, y) {
y >= x@start & y <= x@end
}
OOP System Decision Matrix
S7 vs vctrs vs S3/S4 Decision Tree
Start here: What are you building?
1. Vector-like objects (things that behave like atomic vectors)
Use vctrs when:
- Need data frame integration (columns/rows)
- Want type-stable vector operations
- Building factor-like, date-like, or numeric-like classes
- Need consistent coercion/casting behavior
- Working with existing tidyverse infrastructure
Examples: custom date classes, units, categorical data
2. General objects (complex data structures, not vector-like)
Use S7 when:
- NEW projects that need formal classes
- Want property validation and safe property access (@)
- Need multiple dispatch (beyond S3's double dispatch)
- Converting from S3 and want better structure
- Building class hierarchies with inheritance
- Want better error messages and discoverability
Use S3 when:
- Simple classes with minimal structure needs
- Maximum compatibility and minimal dependencies
- Quick prototyping or internal classes
- Contributing to existing S3-based ecosystems
- Performance is absolutely critical (minimal overhead)
Use S4 when:
- Working in Bioconductor ecosystem
- Need complex multiple inheritance (S7 doesn't support this)
- Existing S4 codebase that works well
Detailed S7 vs S3 Comparison
| Feature | S3 | S7 | When S7 wins |
|---|---|---|---|
| Class definition | Informal (convention) | Formal (new_class()) |
Need guaranteed structure |
| Property access | $ or attr() (unsafe) |
@ (safe, validated) |
Property validation matters |
| Validation | Manual, inconsistent | Built-in validators | Data integrity important |
| Method discovery | Hard to find methods | Clear method printing | Developer experience matters |
| Multiple dispatch | Limited (base generics) | Full multiple dispatch | Complex method dispatch needed |
| Inheritance | Informal, NextMethod() |
Explicit super() |
Predictable inheritance needed |
| Migration cost | - | Low (1-2 hours) | Want better structure |
| Performance | Fastest | ~Same as S3 | Performance difference negligible |
| Compatibility | Full S3 | Full S3 + S7 | Need both old and new patterns |
Practical Guidelines
Choose S7 when you have
# Complex validation needs
Range <- new_class("Range",
properties = list(start = class_double, end = class_double),
validator = function(self) {
if (self@end < self@start) "@end must be >= @start"
}
)
# Multiple dispatch needs
method(generic, list(ClassA, ClassB)) <- function(x, y) ...
# Class hierarchies with clear inheritance
Child <- new_class("Child", parent = Parent)
Choose vctrs when you need
# Vector-like behavior in data frames
percent <- new_vctr(0.5, class = "percentage")
data.frame(x = 1:3, pct = percent(c(0.1, 0.2, 0.3))) # works seamlessly
# Type-stable operations
vec_c(percent(0.1), percent(0.2)) # predictable behavior
vec_cast(0.5, percent()) # explicit, safe casting
Choose S3 when you have
# Simple classes without complex needs
new_simple <- function(x) structure(x, class = "simple")
print.simple <- function(x, ...) cat("Simple:", x)
# Maximum performance needs (rare)
# Existing S3 ecosystem contributions
S3 Patterns
Basic S3 Class
# Constructor
new_person <- function(name, age) {
stopifnot(is.character(name), length(name) == 1)
stopifnot(is.numeric(age), length(age) == 1)
structure(
list(name = name, age = age),
class = "person"
)
}
# Print method
print.person <- function(x, ...) {
cat("Person:", x$name, "(age", x$age, ")\n")
invisible(x)
}
# Generic + method
greet <- function(x) UseMethod("greet")
greet.person <- function(x) {
cat("Hello, my name is", x$name, "\n")
}
greet.default <- function(x) {
cat("Hello!\n")
}
S3 Inheritance
# Child class
new_employee <- function(name, age, company) {
obj <- new_person(name, age)
obj$company <- company
class(obj) <- c("employee", class(obj))
obj
}
# Method with inheritance
print.employee <- function(x, ...) {
NextMethod() # Call parent print method
cat("Works at:", x$company, "\n")
invisible(x)
}
S7 Patterns
Basic S7 Class
library(S7)
# Define class
Person <- new_class("Person",
properties = list(
name = class_character,
age = class_numeric
),
validator = function(self) {
if (self@age < 0) {
"@age must be non-negative"
}
}
)
# Create instance
bob <- Person(name = "Bob", age = 30)
bob@name # "Bob"
bob@age <- 31 # Validated assignment
S7 Methods
# Define generic
greet <- new_generic("greet", "x")
# Add method
method(greet, Person) <- function(x) {
cat("Hello, my name is", x@name, "\n")
}
# Default method
method(greet, class_any) <- function(x) {
cat("Hello!\n")
}
S7 Inheritance
Employee <- new_class("Employee",
parent = Person,
properties = list(
company = class_character
)
)
# Override method
method(greet, Employee) <- function(x) {
super(x, Person)@greet() # Call parent method
cat("I work at", x@company, "\n")
}
S7 Multiple Dispatch
# Generic with multiple dispatch
combine <- new_generic("combine", c("x", "y"))
# Method for specific combination
method(combine, list(Person, Person)) <- function(x, y) {
cat(x@name, "meets", y@name, "\n")
}
method(combine, list(Person, class_character)) <- function(x, y) {
cat(x@name, "receives message:", y, "\n")
}
Migration Strategy
- S3 -> S7: Usually 1-2 hours work, keeps full compatibility
- S4 -> S7: More complex, evaluate if S4 features are actually needed
- Base R -> vctrs: For vector-like classes, significant benefits
- Combining approaches: S7 classes can use vctrs principles internally
Migration Example: S3 to S7
# Original S3
new_person_s3 <- function(name, age) {
structure(list(name = name, age = age), class = "person")
}
# Migrated S7
Person <- new_class("Person",
properties = list(
name = class_character,
age = class_numeric
)
)
# S7 is backwards compatible with S3 generics
# Existing S3 methods still work
When NOT to Use OOP
Sometimes simpler approaches are better:
# Don't create a class for simple data
# BAD
Point <- new_class("Point", properties = list(x = class_double, y = class_double))
# GOOD - just use a named list or vector
point <- c(x = 1.5, y = 2.3)
# Don't create classes for one-off operations
# Use functions instead
distance <- function(p1, p2) {
sqrt((p1["x"] - p2["x"])^2 + (p1["y"] - p2["y"])^2)
}