Issue #14056 has been updated by jeremyevans0 (Jeremy Evans).

Status changed from Open to Rejected

marcandre (Marc-Andre Lafortune) wrote:
> You're completely right for the rest, I got confused as to how private Ruby methods are.
> 
> Glad I could help. And now, even for methods with blocks there wouldn't even be a performance issue :-)
> 
> So we should close the issue, then?

Yes, I'll close it.

----------------------------------------
Feature #14056: Add Module#deprecate_public for deprecation of public methods
https://bugs.ruby-lang.org/issues/14056#change-67607

* Author: jeremyevans0 (Jeremy Evans)
* Status: Rejected
* Priority: Normal
* Assignee: matz (Yukihiro Matsumoto)
* Target version: 
----------------------------------------
The attached patch allows you to make a method private, but have
calling it publicly (either directly or via public_send) emit a
warning instead of raising a NoMethodError.

This is mostly useful in library development, where you want to
continue using a method internally, and you want to disallow external
use, but you want existing external users who are using the method to
receive a warning during a deprecation period instead of breaking their
code immediately.

I believe this feature is not possible without modifying the VM
(as the patch does).  You can emit a deprecation message inside the
method, but I don't believe you can make it conditional on whether the
method was called publicly or privately, as that information isn't exposed.

Use is similar to public/protected/private when called with arguments:

~~~ruby
  class MyClass
    def meth
      1
    end
    deprecate_public :meth
  end

  MyClass.new.meth
  # warning: calling private method meth on #<MyClass:0x00001c896dfb1a90> \
  #   via deprecated public interface
  # => 1
~~~

Module#deprecate_public makes the method private, but sets a flag on
the method entry that it is deprecated, and if calling the method would
usually raise a NoMethodError due to visibility, instead a warning is
printed and then method call works as if it were declared public.

There are some issues with this implementation of deprecate_public:

1) It doesn't handle scope visibility, so the following
   does not work like public/protected/private:

~~~ruby
  class MyClass
    deprecate_public

    def meth
      1
    end
  end
~~~

   Currently, this deprecate_public call would do nothing
   as no arguments were given.  It's probably possible to
   handle scope visibility as well, but it would require
   additional internal changes.

2) It is rather inefficient, as it first exports the method
   in the module as public and then private, before setting
   the deprecation flag.  However, this method is not likely
   to be a bottleneck in any reasonable code.  It was done this
   way to reuse the most existing code and still ensure that
   methods will be setup in the class itself and that method
   caches will be cleared appropriately.

3) When public_send is used, this does not print the receiver
   of the public_send method, instead it prints the module
   that used the deprecate_public call.  I'm not sure whether
   the calling information is available from rb_method_call_status,
   or how to access it if it is available.

4) This doesn't currently handle protected methods, but I
   think changing it to do so isn't too difficult.

5) The method name isn't great, hopefully someone can think of
   a better one that isn't much longer.

---Files--------------------------------
0001-Add-Module-deprecate_public-for-deprecation-of-publi.patch (11.1 KB)


-- 
https://bugs.ruby-lang.org/

Unsubscribe: <mailto:ruby-core-request / ruby-lang.org?subject=unsubscribe>
<http://lists.ruby-lang.org/cgi-bin/mailman/options/ruby-core>