Feature #18915
openNew error class: NotImplementedYetError or scope change for NotImplementedError
Description
Abstract¶
Introduce NotImplementedYetError
exception that should be used in case when the codepath has not been implemented by the developer for some reason (maybe they're designing an abstract class or are designing some sort of interface to reuse later on) OR extend the meaning of NotImplementedError
to cover those usecases so we don't have to introduce another exception
Background¶
NotImplementedError
is supposed to be raised if the underlying operating system or Ruby runtime does not support them
(https://ruby-doc.org/core-3.1.2/NotImplementedError.html)
However it appears that many people are misusing this exception by raising this in a superclass from which they later inherit from. I do realize that Ruby promotes duck-typing (the default RuboCop style guide has a cop for this – https://github.com/rubocop/ruby-style-guide#duck-typing). However I have seen this being discussed numerous times:
- https://github.com/rubocop/ruby-style-guide/issues/458
- http://chrisstump.online/2016/03/23/stop-abusing-notimplementederror/
- https://oleg0potapov.medium.com/ruby-notimplementederror-dont-use-it-dff1fd7228e5
- https://gitlab.com/gitlab-org/gitlab/-/issues/354314 (which I'm the author of)
-
https://github.com/rmosolgo/graphql-ruby/issues/2067 (here the author actually confused it with Python's
NotImplementedError
) - https://stackoverflow.com/questions/13668068/how-to-signal-not-implemented-yet
Proposal¶
Create NotImplementedYetError
exception
OR
Allow raising NotImplementedError
in cases other than OS or Ruby runtime incompatibilities
Evaluation¶
Add NotImplementedYetError
I think a new exception is a better idea than changing the usage of an existing one just because "everyone is using it". That said it would require people to refactor their code which might prevent wider adoption of the new exception.
Change scope of NotImplementedError
This would require the least amount of changes possible (only a documentation change) and I believe there would be no compatibility problems whatsoever.
Files
Updated by Quintasan (Michał Zając) about 2 years ago
- Subject changed from New error class: NotImplementedYetError or scope change for NotImplementedYet to New error class: NotImplementedYetError or scope change for NotImplementedError
Updated by Quintasan (Michał Zając) about 2 years ago
- Description updated (diff)
Updated by austin (Austin Ziegler) about 2 years ago
I think that a PR for a documentation change on this would probably be accepted.
Updated by zdennis (Zach Dennis) about 1 year ago
- File not-implemented-error-docs.patch added
Attached is a patch to update the documentation for NotImplementedError to expand its scope beyond just missing features on the underlying platform.
The current documentation has been in place since just before Ruby 1.9.2. Historically, it appears that Ruby hasn't limited its usage of NotImplementedError to errors that originate from features missing from the underlying platform (e.g. system calls) since at least 1.8.0. I believe the example provided in the current NotImplementedError documentation was meant as an example, not to suggest the only scope in which this error can be used.
Ruby itself invalidates most of the interpretation provided in the Background section of this ticket. Here are just three examples:
- numeric.c raises NotImplementedError when a class needs provide its own <=> method.
- delegate.rb raises NotImplementedError to indicate that a getobj and setobj need to provided by a subclass.
- tsort uses this error and documents it expressly as: Should be implemented by a extended class.
There are more examples to be found in Ruby as well.
Outside of Ruby, this pattern is also commonly used as a way to communicate the intent to an application, framework, or library developer. Here are four examples from popular projects:
- rails uses this pattern
- minitest uses this pattern
- rspec uses this pattern
- dry-rb libraries use this pattern
Additionally, even the latest Programming Ruby 3.2 book by PragPub uses an example of this in Chapter 6: Inheritance and Messages.
Updated by zdennis (Zach Dennis) about 1 year ago
Whoops, last patch upload failed. Patch actually applied here.
Updated by nobu (Nobuyoshi Nakada) about 1 year ago
- File deleted (
not-implemented-error-docs.patch)
Updated by tenderlovemaking (Aaron Patterson) about 1 year ago
I'm guilty of using NotImplementedError
for abstract classes. I like the idea of changing the documentation, but on the other hand, since NotImplementedError
doesn't inherit from StandardError I kind of wish there was a new exception class.
Updated by Quintasan (Michał Zając) about 1 year ago
tenderlovemaking (Aaron Patterson) wrote in #note-8:
I'm guilty of using
NotImplementedError
for abstract classes. I like the idea of changing the documentation, but on the other hand, sinceNotImplementedError
doesn't inherit from StandardError I kind of wish there was a new exception class.
Hence my proposal to introduce a new class. I didn't want to create a PR for either solution because I would welcome both of them. I'm slightly leaning towards a new exception class for this.
Updated by byroot (Jean Boussier) about 1 year ago
since NotImplementedError doesn't inherit from StandardError I kind of wish there was a new exception class
Could you elaborate? For this use case I think not inheriting from StandardError
is better, as it's not something you'd want to be rescued broadly.
Updated by tenderlovemaking (Aaron Patterson) about 1 year ago
byroot (Jean Boussier) wrote in #note-10:
since NotImplementedError doesn't inherit from StandardError I kind of wish there was a new exception class
Could you elaborate? For this use case I think not inheriting from
StandardError
is better, as it's not something you'd want to be rescued broadly.
It is something I would like rescued broadly. For example if I'm test driving a concrete implementation, the test framework needs to specifically rescue NotImplementedError
in order to report the error. I wouldn't expect a test framework to rescue OutOfMemoryError for example, but definitely rescue NotImplementedError.
Updated by byroot (Jean Boussier) about 1 year ago
I wouldn't expect a test framework to rescue OutOfMemoryError for example,
Well Minitest does rescue Exception:
https://github.com/minitest/minitest/blob/6719ad8d8d49779669083f5029ea9a0429c49ff5/lib/minitest/test.rb#L196
Pretty sure RSpec does as well. It's one of the rare justifiable cases for doing so.
Updated by mame (Yusuke Endoh) about 1 year ago
Discussed at the dev meeting. This is tentative, but @matz (Yukihiro Matsumoto) said:
- I don't want to change the documentation of
NotImplementedError
. -
NotImplementedYetError
is too confusing withNotImplementedError
. -
ToBeDefinedError
or something would be better. - I will reply to the ticket.
Please wait for matz's answer.
Updated by matz (Yukihiro Matsumoto) 11 months ago
#note-13 explains my opinion well. What name candidate do you have?
Matz.
Updated by Quintasan (Michał Zając) 11 months ago
Updated by Dan0042 (Daniel DeLorme) 11 months ago
How about raise NoMethodError, "method '#{__method__}' is not implemented in #{self.class}"
Updated by byroot (Jean Boussier) 11 months ago
How about raise NoMethodError
Agreed. If people want an exception that inherits from StandardError
, then NoMethodError
perfectly fits the bill.
I still think that "you forgot to implement this abstract method" shouldn't inherit from StandardError
though, as it risk getting handled by the application and not surface during testing, hence why NotImplementedError
already works great for that use case regardless of what the documentation says.
Amusingly Python has the same error class for that purpose exactly: https://docs.python.org/3/library/exceptions.html#NotImplementedError
exception NotImplementedError
This exception is derived from RuntimeError. In user defined base classes, abstract methods should raise this exception when they require derived classes to override the method, or while the class is being developed to indicate that the real implementation still needs to be added.
Updated by nithinbekal (Nithin Bekal) 8 months ago
What name candidate do you have?
What do you think about the name SubclassResponsibilityError
? As @citizen428 (Michael Kohl) explains here:
Smalltalk had the idiom of implementing abstract methods with the body
self subclassResponsibility
which raises an error.
The name gives a pretty clear indication of what is wrong, and it seems fitting considering Ruby's Smalltalk heritage.
Updated by Dan0042 (Daniel DeLorme) 7 months ago
It's a bit off-topic but does anyone know why NotImplementedError doesn't inherit from StandardError? It seems like it should. If the system doesn't support fork()
then I'd like to see that as a nice message via Rack::ShowExceptions rather than having to dig through logs.
And if you use it for abstract classes then you definitely want that displayed by Rack::ShowExceptions
Updated by Quintasan (Michał Zając) 7 months ago
nithinbekal (Nithin Bekal) wrote in #note-18:
What name candidate do you have?
What do you think about the name
SubclassResponsibilityError
? As @citizen428 (Michael Kohl) explains here:Smalltalk had the idiom of implementing abstract methods with the body
self subclassResponsibility
which raises an error.The name gives a pretty clear indication of what is wrong, and it seems fitting considering Ruby's Smalltalk heritage.
I like this as well as AbstractMethodError