Project

General

Profile

Actions

Feature #18915

open

New error class: NotImplementedYetError or scope change for NotImplementedError

Added by Quintasan (Michał Zając) almost 2 years ago. Updated 9 days ago.

Status:
Open
Assignee:
-
Target version:
-
[ruby-core:109207]

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:

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

not-implemented-error-docs.patch (1.57 KB) not-implemented-error-docs.patch zdennis (Zach Dennis), 10/02/2023 01:12 PM
Actions #1

Updated by Quintasan (Michał Zając) over 1 year ago

  • Subject changed from New error class: NotImplementedYetError or scope change for NotImplementedYet to New error class: NotImplementedYetError or scope change for NotImplementedError
Actions #2

Updated by Quintasan (Michał Zając) over 1 year ago

  • Description updated (diff)

Updated by austin (Austin Ziegler) over 1 year ago

I think that a PR for a documentation change on this would probably be accepted.

Updated by zdennis (Zach Dennis) 7 months 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:

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) 7 months ago

Whoops, last patch upload failed. Patch actually applied here.

Actions #6

Updated by Anonymous 7 months ago


Actions #7

Updated by nobu (Nobuyoshi Nakada) 7 months ago

  • File deleted (not-implemented-error-docs.patch)

Updated by tenderlovemaking (Aaron Patterson) 7 months 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) 7 months 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, since NotImplementedError 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) 7 months 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) 7 months 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) 7 months 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) 6 months 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 with NotImplementedError.
  • ToBeDefinedError or something would be better.
  • I will reply to the ticket.

Please wait for matz's answer.

Updated by matz (Yukihiro Matsumoto) 4 months ago

#note-13 explains my opinion well. What name candidate do you have?

Matz.

Updated by Quintasan (Michał Zając) 4 months ago

matz (Yukihiro Matsumoto) wrote in #note-14:

#note-13 explains my opinion well. What name candidate do you have?

Matz.

How about AbstractMethodError - the same as Java?

Updated by Dan0042 (Daniel DeLorme) 4 months ago

How about raise NoMethodError, "method '#{__method__}' is not implemented in #{self.class}"

Updated by byroot (Jean Boussier) 4 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) 18 days 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) 9 days 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

Actions

Also available in: Atom PDF

Like0
Like0Like0Like0Like0Like0Like0Like0Like1Like1Like0Like0Like0Like0Like0Like0Like0Like0Like0Like0