Project

General

Profile

Actions

Bug #22276

open

alias in a module falls back to Object even in classes not inheriting from Object

Bug #22276: alias in a module falls back to Object even in classes not inheriting from Object

Added by shugo (Shugo Maeda) 3 days ago. Updated 3 days ago.

Status:
Open
Assignee:
-
Target version:
-
ruby -v:
ruby 4.1.0dev (2026-08-28T07:43:16Z master 69b49ac7ae) +PRISM [x86_64-linux]
[ruby-core:126537]

Description

When alias (or alias_method) is used in a module and the method is not found in the module, alias searches the method from Object. So a module can alias a method of Kernel or Object, and the alias works even if the module is later included in a class that does not have Object and Kernel as ancestors:

module M
  alias foo puts
  public :foo
end

class X < BasicObject
  include ::M
end

X.new.foo("hello")  #=> hello

X does not include Kernel, but X.new.foo calls Kernel#puts.

This fallback comes from Ruby 1.8, where Object was the root class, so every class that includes a module always had Object and Kernel as ancestors. Since Ruby 1.9 introduced BasicObject, this is no longer true, but the fallback is unchanged. As discussed in #22273, a module should be able to alias only its own methods and its ancestors' methods, and Object is not an ancestor of a module.

This behavior is intentional in the current implementation. There are tests for it (test_alias_in_module in test/ruby/test_alias.rb for #9663, and "accesses a method defined on Object from Kernel" in spec/ruby/core/module/alias_method_spec.rb), and the documentation of Module#alias_method has an example module Mod; alias_method :orig_exit, :exit; end. So code like module M; alias orig_to_s to_s; end exists, and simply raising NameError will break it.

Possible fixes:

  1. Remove the fallback and raise NameError. This breaks existing code.
  2. Do not resolve the method at alias time. Instead, resolve it at call time from the ancestors of the receiver's class, like ZSUPER methods. Existing code that includes the module in a subclass of Object keeps working, and X.new.foo above raises NoMethodError.
  3. Keep the current behavior and document it.

I think 2 is the best choice for compatibility.

Actions

Also available in: PDF Atom