ruby picture

RCR 239: Module#not_redefining, #redefining, #not_redefinable

Submitted by itsme213 (Thu Apr 08 01:04:24 UTC 2004)

Abstract

Catch method definitions that either accidentally re-define, or accidentally fail to re-define, an existing method.

Problem

Both when subclassing, and when re-opening a class to extend it, a common error is mistakenly overriding (or failing to override) a method. This RCR lets you declare your intent to re-define (or not), and catches errors.

Proposal

Add class methods

Class#redefining

Any method defined while this is in effect should redefine an existing method; otherwise an error is raised

Class#not_redefining

Any method defined while this is in effect should not be redefining an existing method; otherwise an error is raised

Class#not_redefinable

Any method that is defined while this is in effect should not be overriden by any subclass (or extension of this class); otherwise an error is raised

Analysis

Should not affect existing code, unless they already use methods with those names.

Implementation

At least part of this can be accomplished by method_added and traversing the class inheritance and module inclusion structures. Sorry I don't have a full implementation to propose.
ruby picture
Comments Current voting

I think I like the concept here, but I'm not sure I like how you've suggested it. It sounds similar to the "freeze levels" introduced above, but perhaps as a better mechanism. Perhaps:

  class String
    instance_methods.each { |m| freeze_method(m.intern) }
  end  class Foo
    def bar; ...; end
    freeze_method(:bar) # the method cannot be redefined by reopening the class    def baz; ...; end
    virtual_method(:baz) # the method must be redefined children
  end

That's just offered as a thought.

Also, you have Module#... in the title of the RCR, but Class#... in the body. -- Austin Ziegler


Questions:

  1. What happens if I define a method in a derived class without using the redefining() method?
  2. Which error is raised in the cases you indicate an error will be raised?
  3. You indicate in the abstract that this RCR provides a mechanism for catching when a method is failed to be redefined in a derived class. Which of the three methods provides this feature?
  4. What behavior should I expect if neither redefining() nor not_redefining is in effect?
  5. Is there a method to turn off not_redefinable()?

-- Paul Brannan


  1. If method was already declared #not_redefinable then error; otherwise fine
  2. Tbd, consistent with "private method `f' called for #<A:0x2a67858> (NoMethodError)"
  3. Oops. Needs #must_redefine; error would be raised at the "end" of an inheriting or extending class definition.
  4. Exactly today's behavior.
  5. Maybe any/all of these could generate warning instead of errors?
-- Its me


I have a question too: is this really such a big problem in the first place? How often does one "accidentally" redefine (or not) a method? I know that the openness of Ruby classes entails risk as well as reward, but this proposal has a little bit the feel, to me, of trying to patch the language to save it from itself.

I think Austin's redesign makes sense in the context of the proposal, but I don't like the idea of adding non-Ruby concepts like "virtual methods" to Ruby on what I think are shaky grounds.

It seems to me this is a good candidate for a non-core library. Is there any reason not to distribute it that way?

-- David Black


It has no impact on code unless these declarations are used somewhere; when used it helps document and check the re-definition protocol. Like it or not, as libraries grow this becomes important (see Smalltalk, or how today's IDEs try to help with this).


Well, "like it or not" doesn't do much to stimulate further discussion :-) I'll just say that neither the presence of a feature in Smalltalk, nor its presence in IDEs, suggests to me that it has to be in the Ruby core language. In fact an IDE sounds like the right place for this.

-- David Black


Sorry, I didn't mean it to sound like it did. More spelled out: Smalltalk has trouble with this because its libraries have grown but the language itself offers no help, so a Smalltalk IDE must actually figure out quite a bit about the internal structure of a method body to do something useful. IDEs for other languages (e.g. Java) leverage whatever that language offers.

Freeze (as I understand it) operates at the object/class level, not methods, so does something quite different. Similar names between the two might be worthwhile, such as Austin's freeze_method variants, if the interface remains reasonably friendly.

RCR 234 would offer an alternative (and uniform) way to achieve this on a per-method basis using methods on (Unbound)Methods themselves. Exact position of the "freeze" not too critical right here imho.

   def foo() ... end . freeze (optional_freeze_specs)


I actually agree more with David on this. I think that this is a solution in search of a problem, and is better served by the "freeze levels" proposal, although as I said, this might be a better interface. The "virtual_method" was mostly a shifting of the terminology to something that makes more sense than I think is specified in the original RCR. I could see using a "freeze_method", but only rarely. It doesn't feel like anything that I would actually ever use in my Ruby programming. -- Austin Ziegler

Add new comments here.


Strongly opposed 4
Opposed 2
Neutral 0
In favor 0
Strongly advocate 0
ruby picture
If you have registered at RCRchive, you may now sign in below. If you have not registered, you may sign up for a username and password. Registering enables you to submit new RCRs, and vote and leave comments on existing RCRs.
Your username:
Your password:

ruby picture

Powered by .