Sometimes I want to be certain I'm not clobbering/masking a method:
class Dog
def bark
'bark!'
end
end
class Poodle < Dog
raise if method_defined? :bark
def bark
'bow-wow'
end
end
I propose creating a shorthand. Maybe something like:
class Dog
def bark
'bark!'
end
end
class Poodle < Dog
ncdef bark # "no clobber" def
'bow-wow'
end
end
=> #<MethodAlreadyDefined: Method `bark' already defined.>
This would be useful in scenarios where subclassing a class (or including a mixin) you don't own is common practice --for instance, subclassing ApplicationRecord for your model in Rails.
I like this idea.
But no one will use this feature if you need to always opt-in via ncdef.
It would make more sense as a $VERBOSE warning that can be turned off when you know you want to clobber.
classDogdefa;enddefb;enddefb;end#=> already has a warning; avoid by using `undef b`endclassPoodle<Dogno_clobber!#maybe turn on warnings for this class via DSL?defa;super;end#=> no warning due to `super` keyword in methoddefb;end#=> warning; avoid by using `undef b`end
Support for final methods would allow libraries and application developers to clearly communicate what methods of a class can be overridden and which ones should not. Active Record objects are a good example. If someone defines a method called ‘create_record’ they will be in trouble and the library could mark that method as final to avoid that mistake.
Override can be paired with final to allow the users to explicitly tell they are aware they are overriding a final method. Although, in that case the name ‘final’ doesn’t make much sense.
Ah, forgot to say sorbet already have support to final, abstract and override. Having support in Ruby could help with static analysis in sorbet and steep.
Isn’t this the same idea as final methods in other languages like Java?
Had this discussion with a coworker --final is similar but is for the opposite direction. final lets the library author prevent overriding; I'm wanting a tool as the library consumer to avoid accidental overriding.
A library author using final definitely does solve my problem, but then the onus is on the author (and I'm much more often the library consumer).
@Dan0042 I like that syntax --much more convenient-- but I don't know if it would be useful to me if it were just toggling the existing warning.
But that syntax seems great:
classMyClass<LibraryProvidedClassno_clobberdefa;enddefb;super;end# no effect (`super` being called) defc;endoverridedefd;end# maybe an override keyword to use in conjunction with `no_clobber`?end=>#<MethodAlreadyDefined: Method `c' already defined.>
classMyClass<LibraryProvidedClassdefa;endno_clobberdefb;end# can also be used in a one-off way like `private`defc;endend
The fact that you want to raise an error suggests that you want this feature to take place during development, and not during production: You want to be notified when writing code so that you do not accidentally overwrite a method. If a new method overwrites an old one, then you want to remove the new definition entirely from the code, and if it does not, then you just want to end up with an ordinary def block in the final production code.
If that is the case, I think such feature would be the responsibility of an IDE, and not of the Ruby implementation.
Or, if that is not the case, and you want to keep the definition in the code base regardless of whether it overwrites or not, but not let the overwriting take effect, then in such case, I think you need some different mechanism, and your proposal here would be in the wrong direction.