From 27e14c16c42d775e84ddb087cfda88c7b828b940 Mon Sep 17 00:00:00 2001 From: "Yukihiro \"Matz\" Matsumoto" Date: Tue, 12 May 2026 22:33:09 +0900 Subject: [PATCH] limitations.md: document Class#initialize re-invocation difference mruby's Class#initialize accepts re-invocation through __send__ silently, while CRuby raises TypeError. The superclass argument is ignored on re-invocation, so no destructive side effect is possible. Reported on Twitter by cacao_soft. Co-authored-by: Claude --- doc/limitations.md | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) diff --git a/doc/limitations.md b/doc/limitations.md index 8fae52116..4d8fc4708 100644 --- a/doc/limitations.md +++ b/doc/limitations.md @@ -404,3 +404,37 @@ LocalJumpError # always raised — the dup is orphan from the moment mruby's stricter rule keeps `RProc` from needing a back-pointer to the original block (which would also enlarge the GC mark set). + +## `Class#initialize` Can Be Re-Invoked + +CRuby raises `TypeError: already initialized class` when `initialize` +is invoked on a class that has already been set up. mruby's +`Class#initialize` has no such guard — invoking it on an existing +class through `__send__`, `send`, or `UnboundMethod#bind_call` +silently succeeds. The superclass argument is ignored in this case, +so the call cannot rewrite the class hierarchy; only the block (if +any) is evaluated with the class as receiver. + +```ruby +Klass = Class.new +Klass.__send__(:initialize) {} +``` + +#### CRuby + +``` +TypeError: already initialized class +``` + +#### mruby + +``` +The block is evaluated in the context of Klass; no error is raised. +The superclass is not changed even when one is passed as an argument. +``` + +`Module#initialize` is re-callable in both implementations, so this +divergence is `Class`-specific. Adding the CRuby check would require +an additional flag bit on every `RClass`; mruby leaves the bit +unspent because no destructive side effects are possible through +this path.