Project

General

Profile

Actions

Feature #14056

closed

Add Module#deprecate_public for deprecation of public methods

Added by jeremyevans0 (Jeremy Evans) over 7 years ago. Updated over 7 years ago.

Status:
Rejected
Target version:
-
[ruby-core:83568]

Description

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:

  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:
  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.

  1. 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.

  2. 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.

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

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


Files

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0