Skip to content
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

Add rule about not extending Data.define #917

Merged
merged 3 commits into from
Mar 27, 2023

Conversation

ktopolski
Copy link
Contributor

See also:

I was wondering about two things in this PR:

  1. Whether I should place it close to [[no-extend-struct-new]] rule. Decided to just append to the end of the guide eventually.
  2. Whether or not I should change the [[struct-new]] rule to using Data.define instead. Kinda depends on the use case, but I'd assume Data.define should be the default for rubies 3.2+ 🤔 Looking forward to the discussion here, I'm open to adding this change to this PR(or opening new PR for that)

@pirj
Copy link
Member

pirj commented Mar 26, 2023

should place it close to [[no-extend-struct-new]] rule.

I'd say yes.

should change the [[struct-new]] rule to using Data.define instead

In separate PR - yes. Let's keep the Struct.new there, since it's still the only available option for most.

See also:
* [PR adding new cop for this rule](rubocop/rubocop#11728)
* [Original issue](rubocop/rubocop#11696)
@ktopolski ktopolski force-pushed the add_no_extend_data_define_rule branch from 1f15b25 to dceb7bb Compare March 26, 2023 21:55
README.adoc Outdated
=== Don't Extend `Data.define` [[no-extend-data-define]]

Don't extend an instance initialized by `Data.define`.
Extending it introduces a superfluous class level and may also introduce weird errors if the file is required multiple times.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

introduce weird errors if the file is required multiple times

I don't really get this part.

class A < Data.define(:x); end
class A < Data.define(:x); end # => TypeError: superclass mismatch for class A
class B < Struct.new(:x); end
class B < Struct.new(:x); end # => TypeError: superclass mismatch for class B

Also, require docs:

Loads the given name, returning true if successful and false if the feature is already loaded.

Copy link
Contributor Author

@ktopolski ktopolski Mar 26, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice catch! I think I must've forgot to remove the part about introduce weird errors... when I copied and adjusted the description from the [[no-extend-struct-new]].

I guess now the question is - what did the author of [[no-extend-struct-new]] meant there by weird errors and if it's still relevant 🤔

I'll remove the part after and, thank you!

@pirj
Copy link
Member

pirj commented Mar 26, 2023

define(name, *symbols) → class
Defines a new Data class. If the first argument is a string, the class is stored in Data::<name> constant.

Does it really? cc @zverok

E = Data.define('Foo', :x)
Data::Foo # => NameError: uninitialized constant Data::Foo

@ktopolski
Copy link
Contributor Author

I'd say yes.

Alright, changed the order so [[no-extend-data-define]] appears straight after [[no-extend-struct-new]]

In separate PR - yes. Let's keep the Struct.new there, since it's still the only available option for most.

I don't get this part, sorry! Got confused hwew:

In separate PR - yes. Let's keep the Struct.new there

By there you mean this PR, or in general the [[struct-new]] rule? 🤔 I'm not sure if I should open another PR to change [[struct-new]] to use Data(as you mentioned - that would be for minorities) or open another PR to add the [[data-new]] rule, or something else is suggested? 😅

----
# bad
class Person < Data.define(:first_name, :last_name)
end
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think it will also be a good idea to show the output of Person.ancestors in both examples to show clearly the anonymous class that gets added there.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Done! Do you think I should open another one to illustrate this for [[no-extend-struct-new]] too?

@zverok
Copy link
Contributor

zverok commented Mar 27, 2023

Does it really? cc @zverok

It does not. It did in initial implementation (for feature parity with Struct), but other core devs suggested that this function for Struct was legacy and there is no value in reproducing it in Data

@zverok
Copy link
Contributor

zverok commented Mar 27, 2023

NB: I am not sure how valuable this input is, but there are cases when classic inheritance from Data.define is useful: see my blogpost about initialization, "You need to be mindful redefining #initialize" section (classic subclassing allows to use super in redefined new)

@bbatsov bbatsov merged commit c9929f7 into rubocop:master Mar 27, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

None yet

4 participants