New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Lint/MissingSuper false positive #8506
Comments
There's also a request to have a list of accepted superclasse exceptions, would that resolve the issue for you? I'm curious of examples where there are good reasons to explicitly not call |
👍 |
Not really. I just don't think this should be a rubocop.
One concern would be for performance (though this is not a primary concern). Another is that this makes the code harder to read as I might have to navigate to another file to see what logic is happening there (and this could be hard to find if it's in a gem). Mostly I'm concerned that this is not idiomatic for libraries like view_component (https://github.com/github/view_component#implementation) If a new coder sees |
The idea is that if there was no That said, if others feel this Cop should be disabled by default, I won't stand in the way. |
Sorbet is one counter-example where you don't want to call super necessarily, born out of @will's post on standard standardrb/standard#195 It'd be really awesome if this was configurable for which callbacks, because I think there are fewer cases where you'd intentionally skip calling super on |
Speaking of those two cases (notice no parent class): class Foo
def method_missing(*args)
super class Foo
def self.inherited(base)
super Is PS Also here module M
def self.included(base)
super |
Yes, without parent classes those are not really strictly necessary. |
Not necessary, but can't hurt. class Foo
extend ModDependingOnInheritedCallback
def self.inherited(base)
super or # base.rb
class Foo < Bar
# ...
# extension.rb
class Foo
def self.inherited |
Here's an example of Falling back to |
This creates a new mixin, Callable, which can be used to provide a class with the boilerplate so that it can have a public class method of `.call` which calls `#initialize` with the arguments and then `#call`. This mixin replaces the inheritance approach used in services with an ApplicationService class. These classes now all utilise this mixin instead. The reason for doing this was prompted by a linting violation with one of rubocop's newer rules: `Lint/MissingSuper`, which is an offence when a class inherits but does not call `super` in it's initialize method. This violation seemed to only affect some of GOV.UK's newer code, such as this service pattern, which led to some debate [1] about what the most appropriate means to share this behaviour is, whether our inheritance approach was actually idiomatic and how using super in every `initialize` would be unnecessary boilerplate. The Rubocop thread [2] regarding this rule raised an interesting point "I'm curious of examples where there are good reasons to explicitly not call super.", which led to me considering why we didn't think `super` would be appropriate in these classes. My conclusion to this was that we weren't actually intending to create a subtype with inheritance, we actually just wanted standardisation with the interface, and that the inherited classes have very little behavioural consistency, breaking Liskov substitution principle [3]. When looking at the Ruby standard library a module seems the most appropriate way to implement it, considering similarities with modules such as Singleton and Enumerable. Taking inspiration from the Ruby standard library there is an in [1]: alphagov/rubocop-govuk#125 [2]: rubocop/rubocop#8506 [3]: https://thoughtbot.com/blog/back-to-basics-solid#liskov-substitution-principle
This creates a new mixin, Callable, which can be used to provide a class with the boilerplate so that it can have a public class method of `.call` which calls `#initialize` with the arguments and then `#call`. This mixin replaces the inheritance approach used in services with an ApplicationService class. These classes now all utilise this mixin instead. The change was prompted by a linting violation with one of rubocop's newer rules: `Lint/MissingSuper`, which is an offence when a class inherits but does not call `super` in it's initialize method. This violation seemed to only affect some of GOV.UK's newer code, such as this service pattern, which led to some debate [1] about what the most appropriate means to share this behaviour is, whether our inheritance approach was actually idiomatic and how using super in every `initialize` would be unnecessary boilerplate. The Rubocop thread [2] regarding this rule raised an interesting point "I'm curious of examples where there are good reasons to explicitly not call super.", which led to me considering why we didn't think `super` would be appropriate in these classes. My conclusion to this was that we weren't actually intending to create a subtype with inheritance, we actually just wanted standardisation with the interface, and that the inherited classes have very little behavioural consistency, breaking Liskov substitution principle [3]. When looking at the Ruby standard library a module seems the most appropriate way to implement it, considering similarities with Singleton and Enumerable. [1]: alphagov/rubocop-govuk#125 [2]: rubocop/rubocop#8506 [3]: https://thoughtbot.com/blog/back-to-basics-solid#liskov-substitution-principle
This creates a new mixin, Callable, which can be used to provide a class with the boilerplate so that it can have a public class method of `.call` which calls `#initialize` with the arguments and then `#call`. The creation of this class is a port of the same approach applied in Content Publisher [1] (and most of this commit message is a port too in case you're feeling a touch of déjà vu). This mixin replaces the inheritance approach used in builders, presenters and services. The change was prompted by a linting violation with one of rubocop's newer rules: `Lint/MissingSuper`, which is an offence when a class inherits but does not call `super` in it's initialize method. This violation seemed to only affect some of GOV.UK's newer code, such as this service pattern, which led to some debate [2] about what the most appropriate means to share this behaviour is, whether our inheritance approach was actually idiomatic and how using super in every `initialize` would be unnecessary boilerplate. The Rubocop thread [3] regarding this rule raised an interesting point "I'm curious of examples where there are good reasons to explicitly not call super.", which led to me considering why we didn't think `super` would be appropriate in these classes. My conclusion to this was that we weren't actually intending to create a subtype with inheritance, we actually just wanted standardisation with the interface, and that the inherited classes have very little behavioural consistency, breaking Liskov substitution principle [4]. When looking at the Ruby standard library a module seems the most appropriate way to implement it, considering similarities with Singleton and Enumerable. [1]: alphagov/content-publisher@5933f87 [2]: alphagov/rubocop-govuk#125 [3]: rubocop/rubocop#8506 [4]: https://thoughtbot.com/blog/back-to-basics-solid#liskov-substitution-principle
This creates a new mixin, Callable, which can be used to provide a class with the boilerplate so that it can have a public class method of `.call` which calls `#initialize` with the arguments and then `#call`. The creation of this class is a port of the same approach applied in Content Publisher [1] (and most of this commit message is a port too in case you're feeling a touch of déjà vu). This mixin replaces the inheritance approach used in builders, presenters and services. The change was prompted by a linting violation with one of rubocop's newer rules: `Lint/MissingSuper`, which is an offence when a class inherits but does not call `super` in it's initialize method. This violation seemed to only affect some of GOV.UK's newer code, such as this service pattern, which led to some debate [2] about what the most appropriate means to share this behaviour is, whether our inheritance approach was actually idiomatic and how using super in every `initialize` would be unnecessary boilerplate. The Rubocop thread [3] regarding this rule raised an interesting point "I'm curious of examples where there are good reasons to explicitly not call super.", which led to me considering why we didn't think `super` would be appropriate in these classes. My conclusion to this was that we weren't actually intending to create a subtype with inheritance, we actually just wanted standardisation with the interface, and that the inherited classes have very little behavioural consistency, breaking Liskov substitution principle [4]. When looking at the Ruby standard library a module seems the most appropriate way to implement it, considering similarities with Singleton and Enumerable. [1]: alphagov/content-publisher@5933f87 [2]: alphagov/rubocop-govuk#125 [3]: rubocop/rubocop#8506 [4]: https://thoughtbot.com/blog/back-to-basics-solid#liskov-substitution-principle
This creates a new mixin, Callable, which can be used to provide a class with the boilerplate so that it can have a public class method of `.call` which calls `#initialize` with the arguments and then `#call`. The creation of this class is a port of the same approach applied in Content Publisher [1] (and most of this commit message is a port too in case you're feeling a touch of déjà vu). This mixin replaces the inheritance approach used in builders, presenters and services. The change was prompted by a linting violation with one of rubocop's newer rules: `Lint/MissingSuper`, which is an offence when a class inherits but does not call `super` in it's initialize method. This violation seemed to only affect some of GOV.UK's newer code, such as this service pattern, which led to some debate [2] about what the most appropriate means to share this behaviour is, whether our inheritance approach was actually idiomatic and how using super in every `initialize` would be unnecessary boilerplate. The Rubocop thread [3] regarding this rule raised an interesting point "I'm curious of examples where there are good reasons to explicitly not call super.", which led to me considering why we didn't think `super` would be appropriate in these classes. My conclusion to this was that we weren't actually intending to create a subtype with inheritance, we actually just wanted standardisation with the interface, and that the inherited classes have very little behavioural consistency, breaking Liskov substitution principle [4]. When looking at the Ruby standard library a module seems the most appropriate way to implement it, considering similarities with Singleton and Enumerable. [1]: alphagov/content-publisher@5933f87 [2]: alphagov/rubocop-govuk#125 [3]: rubocop/rubocop#8506 [4]: https://thoughtbot.com/blog/back-to-basics-solid#liskov-substitution-principle
I just bumped into this with some Exception classes. To me, the exception to this rule is that the ancestors of a class do not initialize ivars. Of course, a static tool is going to be hard pressed to keep up with every possible case. However, it seems to me that the vast bulk of these exceptions can be caught without too much trouble.
Because it's REALLY annoying to write: class MyError < RuntimeError
# rubocop:disable Lint/MissingSuper
def initialize(var)
@ivar = var
end
# rubocop:enable Lint/MissingSuper |
I've just run into the same issue when creating a dsl and using self.inherited() only once in the base class. It would be nice if that edge case was considered by this cop. Though at the end of the day it's not too hard to just write a one line exception to the rule. def self.inherited(subclass) # rubocop:disable Lint/MissingSuper |
@marcandre, how come nothing happened with this?
This would definitely solve my problem, while allowing me to keep the cop everywhere else. |
I bumped into this same issue today, my use-case is also related to Sorbet and it's ability to define abstract classes. So I've taken the freedom to open a PR to make StatelessClasses configurable 😄 |
…rable-stateless-classes [Fix #8506] Add AllowedParentClasses config to Lint/MissingSuper.
Thanks @koic! |
There are cases where I'm explicitly avoiding calling
super
in an initializer, however this cop complains on all of them. This doesn't seem very useful.The text was updated successfully, but these errors were encountered: