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

Remove existing rule MandatoryBracesIfStatements #2962

Closed
veyndan opened this issue Aug 11, 2020 · 22 comments
Closed

Remove existing rule MandatoryBracesIfStatements #2962

veyndan opened this issue Aug 11, 2020 · 22 comments

Comments

@veyndan
Copy link
Contributor

veyndan commented Aug 11, 2020

The rules MandatoryBracesIfStatements and MultiLineIfElse appear to achieve the same thing. I'd nominate to remove MandatoryBracesIfStatements over MultiLineIfElse because MultiLineIfElse is maintained by ktlint (which avoids duplication in improvements/bug fixes) and MultiLineIfElse has the possibility for auto-correction.

@schalkms
Copy link
Member

The suggestion is good. However, this rule needs practically 0 maintenance effort.
Furthermore, there are users, who don't use the formatting ruleset and ktlint at all.
I think we should keep it as it is for now. We can surely reconsider, if the maintenance effort rises.
More duplicated rules exist AFAIK.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 11, 2020

However, this rule needs practically 0 maintenance effort.

That's not totally true, as a couple of months ago a false negative had to be fixed for this rule (#2835). It can be imagined that a future case arises again.

Furthermore, there are users, who don't use the formatting ruleset and ktlint at all.

Maybe I'm missing something, but I don't see the issue with deprecating MandatoryBracesIfStatements and telling the users to replace its usage with MultiLineIfElse.

More duplicated rules exist AFAIK.

From the talk by @Mauin, he says that all formatting rules had been stripped from detekt as ktlint does a really good job with that already. Even though MandatoryBracesIfStatements is under the style ruleset, it is still fundamentally a formatting rule.

I know this can be a tentative issue, but I'd love to have some further discussions before being closed.

@schalkms
Copy link
Member

schalkms commented Aug 11, 2020

From the talk by @Mauin, he says that all formatting rules had been stripped from detekt as ktlint does a really good job with that already.

This information is a bit outdated. Previously, detekt had it’s own formatting rules that messed around with user code. The detekt team decided to wrap ktlint and remove rules that were manipulating user code.
The mentioned rule belongs to the style ruleset. That’s a different story.

Please see it this way. The user has the choice, whether user code should be replaced or not.

Maybe I'm missing something, but I don't see the issue with deprecating MandatoryBracesIfStatements and telling the users to replace its usage with MultiLineIfElse.

The rules serve kind of a different use case as mentioned above. The choice is up to the user.
Sure, there’s always a maintenance cost. There’s no free lunch. That’s the reason, why I said close to 0.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 11, 2020

Previously, detekt had it’s own formatting rules that messed around with user code. The detekt team decided to wrap ktlint and remove rules that were manipulating user code.

But the autoCorrect flag is still available in detekt which manipulates user code…

The mentioned rule belongs to the style ruleset.

As both of these rules do the exact same thing, I don't see how it matters what rulesets each of them belongs to.

The user has the choice, whether user code should be replaced or not.

I understand, but that's why there is the autoCorrect field. If they don't want the tool to automatically correct the code, they can just set this field to false in the yml.

The rules serve kind of a different use case as mentioned above. The choice is up to the user.

The way I see it is that MandatoryBracesIfStatements is equivalent to MultiLineIfElse with autoCorrect=false.

@arturbosch @BraisGabin @cortinico Maybe I'm missing something here, do you care to chime in?

@schalkms
Copy link
Member

But the autoCorrect flag is still available in detekt which manipulates user code…

It’s only available in the formatting ruleset, which entirely wraps ktlint rules. autocorrect is just available for this ruleset.

As both of these rules do the exact same thing, I don't see how it matters what rulesets each of them belongs to.

The formatting ruleset consists entirely of ktlint rules. The style ruleset on the other hand consists of detekt native rules.

I understand, but that's why there is the autoCorrect field.

Because ktlint automatically formats user code according to the guidelines. Detekt doesn’t do that. That’s the difference. Ktlint is a linter, detekt a static analysis tool. Both tools serve a different purpose, but integrate nicely with each other.

@schalkms
Copy link
Member

schalkms commented Aug 11, 2020

I hope that I could clear out all doubts and answer all questions @veyndan

@veyndan
Copy link
Contributor Author

veyndan commented Aug 11, 2020

Hmm, I feel that you're just explaining the status quo to me (which I already understand). Let me rephrase the question:

Why would I (a detekt user) prefer MandatoryBracesIfStatements over MultiLineIfElse?

@schalkms
Copy link
Member

Okay. Let me answer the following question.

Why would I (a detekt user) prefer MandatoryBracesIfStatements over MultiLineIfElse?

If a user doesn’t want to use the ktlint wrapper or has ktlint as a separate tool in use, MandatoryBracesIfStatements might be the better choice.

The same holds true for the MaxLineLength rule, for instance.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 12, 2020

Thanks for the answer! Just a couple of further questions on your answer.

If a user […] has ktlint as a separate tool in use, MandatoryBracesIfStatements might be the better choice.

Surely if they are using ktlint as a separate tool (and they have enabled MultiLineIfElse) why would they also enable MandatoryBracesIfStatements?

If a user doesn’t want to use the ktlint wrapper […], MandatoryBracesIfStatements might be the better choice.

Why would a user not want to use the ktlint wrapper and use detekt in isolation (i.e., without ktlint as a separate tool)?

@BraisGabin
Copy link
Member

I think that, right now, we can't remove it.

My reasons:

  • Ktlint MultiLineIfElse is experimental, so ktlint users can't use it completely. (I don't use detekt-formatting, I use ktlint directly but I had some bad expiriences with ktlint experimental so I don't enable them).
  • Remove this rule is a breaking change. We should wait to 2.0 if we want to do it.

Other duplicated rules detekt/ktlint:

  • MaxLineLength
  • NewLineAtEndOfFile
  • SpacingBetweenPackageAndImports
  • WildcardImport - even duplicated... I think that a user that doesn't care about formatting can want this rule. Probably this duplication is completely fine.

@schalkms what do you think about reconsider this for 2.0?

Good thing: Now that I know that ktlin implemented this rule I'll reported them the case that I fixed in #2835 because, at least, they don't have any test to ensure that such case is ok.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 12, 2020

Thanks @BraisGabin! Those reasons make sense. I'd be happy with reopening this issue and adding it to the 2.0 milestone 😄

@schalkms
Copy link
Member

@schalkms what do you think about reconsider this for 2.0?

If detekt is that far we can reconsider or reopen this ofc. At the moment, this is not the case due to all of the mentioned points. That's why I closed it.

@schalkms
Copy link
Member

schalkms commented Aug 12, 2020

Surely if they are using ktlint as a separate tool (and they have enabled MultiLineIfElse) why would they also enable MandatoryBracesIfStatements?

A linter has a different purpose compared to a static analysis tool. A linter most likely runs only on the client, whereas a static analysis tool should run on the CI, if there's any. Detekt has a reporting functionality that ktlint has not.

Why would a user not want to use the ktlint wrapper and use detekt in isolation (i.e., without ktlint as a separate tool)?

Brais already answered this. Additionally, manipulating user code can always lead to unwanted results.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 12, 2020

A linter most likely runs only on the client, whereas a static analysis tool should additionally run on the CI, if there's any.

Okay, let's have an example. You run ktlint on the client with MultiLineIfElse enabled and everything passes. You then run the CI build where ktlint and detekt is enabled. Now the MultiLineIfElse rule will run from ktlint, but also MandatoryBracesIfStatements will run from detekt. Both these rules do the same thing, so running MandatoryBracesIfStatements is completely redundant.

Brais already answered this.

In this case, it is an experimental rule (even though in detekt we don't differentiate that in the documentation). What about a non-experimental rule like NewLineAtEndOfFile which is also duplicated?

Additionally, manipulating user code can always lead to unwanted results.

I've already responded to this above regarding enabling or disabling autoCorrect.

@BraisGabin
Copy link
Member

I moved this idea to #2680 where we have all the ideas for 2.0

@schalkms
Copy link
Member

Why did you enable ktlint as a linter on your CI?
Activating both detekt rules on 1 client is redundant, yes. However, what's the issue with that? How does it hinder you when using detekt?

@veyndan
Copy link
Contributor Author

veyndan commented Aug 12, 2020

Why did you enable ktlint as a linter on your CI?

You mentioned in the last comment that you enabled ktlint and detekt on the CI. Added bold for emphasis:

  • A linter most likely runs only on the client, whereas a static analysis tool should additionally run on the CI, if there's any.

Activating both detekt rules on 1 client is redundant, yes.

This just furthers the question that I've been asking all this time: if activating both detekt rules is redundant, then why should we have both detekt rules (in the long run)?

How does it hinder you when using detekt?

I enabled MandatoryBracesIfStatements with auto correct in my project, hoping that it would fix all the problems. I then noticed that I was looking for MultiLineIfElse instead. It is very confusing having two rules that do the same thing, particularly when one has more advanced features than the other.

The second reason is maintainability of the project and sharing knowledge between ktlint and detekt. Some projects I work with only use ktlint, while others use detekt. If I (or anyone else) finds a bug in ktlint, I'd love to see it propagated to detekt instead of having to make another PR for the duplicate detekt rule.

@schalkms
Copy link
Member

Thanks for the respons!

A linter most likely runs only on the client, whereas a static analysis tool should additionally run on the CI, if there's any.

I removed it in order to sort out further confusion. This is what I meant regarding the tool usage.
Ktlint = client
Detekt = client + server

Whilst both rules might do the same, the inner workings of both rules are different. The ktlint rule does only consider mandatory braces for if statements but not for loops.

https://github.com/pinterest/ktlint/blob/1fa75c63b0708bd7f4c873d610053a632450e453/ktlint-ruleset-experimental/src/main/kotlin/com/pinterest/ktlint/ruleset/experimental/MultiLineIfElseRule.kt#L19

As a side-note, I also understand that it might be confusing.

@schalkms
Copy link
Member

To conclude this conversation, both mentioned rules don't work the same.
MandatoryBracesIfStatements considers more cases than MultiLineIfElse. We should be careful here when removing rules, just because they seem to do the same.

@veyndan
Copy link
Contributor Author

veyndan commented Aug 12, 2020

Ah must've missed that comment! @BraisGabin said in #2680 (comment) that he'll create an issue on ktlint to resolve this.

I think the other rules that @BraisGabin mentioned in #2680 (comment) still apply though, I just happened to choose an experimental rule that is doing stuff out of the scope of its name 😅 .

I agree that we should conclude the discussion though as it's getting pretty long 😂 As it's already linked in #2680, when the talks about detekt 2.0 come around, we can resume the conversation then if that's good for you.

@BraisGabin
Copy link
Member

The issue: pinterest/ktlint#828

And as @schalkms say it seems for pinterest/ktlint#812 MandatoryBracesIfStatements and MultiLineIfElse are not going to be the same. I know that ktlint follows the kotlin coding convention really tight. And the convention doesn't talk about this case:

if (true)
  50
else 
  55

So I imagine that they will rollback that part of the rule 🤷‍♂️. They will probably maintain it for --android... I'm not a huge fan of that decission but I understand it's position.

@arturbosch
Copy link
Member

It is really unfortunately for the user that there are similar/identical rules. I think we can improve the docs further to help them here.
From a tool perspective it makes sense to have the original rule and the additional by the KtLint wrapper for the broadest audience:

  • only detekt-rules users who use all the same IDE
  • detekt-rules + ktfmt
  • detekt-rules + detekt-formatting (single config)
  • detekt-rules + KtLint (multiple configs)
  • detekt + other intern formatters

Why you might prefer MandatoryBracesIfStatements over MultiLineIfElse?
-> annotation (on file class or statement level) + baseline suppression possibility; -> that's why sonar-kotlin excludes KtLint duplicates not the detekt ones.
-> for rule authors: generally detekt issues are easier to post-process due to an attached KtElement on the issue

There is often a overlap of rules between tools e.g. pmd, checkstyle and sonarqube have rules which detect classic code smells like LongMethod's and LongParameterLists. Sonarqube allows to include checkstyle and pmd as plugins. Should sonar remove it's core rules for the others? No, they may also address different users.
Sonarqube moved away of just including pmd and checkstyle and support just their rulesets because they do not wanted to reparse all Java files three times -> saves time on CI/analysis.

What we can do is some kind of mapping. If a detekt rule detects something similar as a KtLint we only report once.
We have the aliases feature for this.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

4 participants