Skip to content

Loading…

alias_method alters visibility #1923

Closed
ngollan opened this Issue · 4 comments

2 participants

@ngollan

(edit: probably works not just with #initialize, so I changed the subject a few minutes after creation…)

When using alias_method to chain #initialize, the receiving class gains a public #initialize. This can lead to weird behaviour in code that makes heavy use of chaining and undefines methods based on visibility.

One affected codebase is Capistrano.

Reproduce with:

module Publicize
  def self.included(base)
    puts "Before: do we have #initialize? #{base.instance_methods.include?(:initialize) ? 'Yes' : 'No'}"
    puts "        ... private? #{base.private_methods.include?(:initialize) ? 'Yes' : 'No'}"

    base.send :alias_method, :old_initialize, :initialize
    base.send :alias_method, :initialize, :outer_initialize

    puts "After: do we have #initialize? #{base.instance_methods.include?(:initialize) ? 'Yes' : 'No'}"
    puts "       ... private? #{base.private_methods.include?(:initialize) ? 'Yes' : 'No'}"
  end

  def outer_initialize(*args)
    old_initialize(*args)
  end
end

class ThatSimple
  include Publicize
end

On MRI 1.9.3, that yields:

Before: do we have #initialize? No
        ... private? Yes
After: do we have #initialize? No
       ... private? Yes

while on RBX master, I get:

Before: do we have #initialize? No
        ... private? Yes
After: do we have #initialize? Yes
       ... private? Yes

Note that RBX now shows #initialize as both public and private.

@ngollan

After correcting the misuse of private_methods which of course was looking at the class, things look like that: https://gist.github.com/99502f6bab062c18c328

So only the initialize method appears to be affected.

@ngollan

dbussink and I did some further digging, and it looks like a difference between 1.8 and 1.9 MRI.

MRI 1.8 has the same behaviour as rbx: Aliasing a method to the constructor results in a public #initialize method; however, in MRI 1.9, the constructor remains private through aliasing.

@Peeja

So to clarify:

We're missing a spec for 1.9 mode that says using alias_method :initialize, :foo, where #foo is a public method, should not make #initialize a public method, as well as the implementation to make that pass.

That is, running https://gist.github.com/99502f6bab062c18c328#file_test3.rb under rbx in 1.9 mode should print true, true, like MRI 1.9.3.

Is that correct?

@ngollan

Yes, that sounds good as far as I can remember.

@dbussink dbussink closed this in #2523
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Something went wrong with that request. Please try again.