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

ktlint 1.1.0 incorrectly reports backing property name error when public-facing variable is internal #2448

Closed
mlewandowskipt opened this issue Dec 20, 2023 · 7 comments

Comments

@mlewandowskipt
Copy link

Expected Behavior

property-naming error is not reported when there is backing property used and the public-facing variable is internal (that's the behavior of ktlint 1.0.1)

Observed Behavior

ktlint 1.1.0 reports property-naming error when the public-facing variable is internal.

Backing property name is only allowed when a matching public property or function exists (standard:property-naming)

Steps to Reproduce

You can use following or similar code to reproduce the issue

private val _elementList = mutableListOf<Element>()
internal val elementList: List<Element>
    get() = _elementList

When internal is removed from elementList, the error is gone. However, I want to be able to use backing property pattern, and hide the property from other modules at the same time.

@paul-dingemans
Copy link
Collaborator

This is introduced in #2346 because according to Kotlin Coding conventions:

If a class has two properties which are conceptually the same but one is part of a public API and another is an implementation detail, use an underscore as the prefix for the name of the private property:

@paul-dingemans paul-dingemans closed this as not planned Won't fix, can't repro, duplicate, stale Dec 21, 2023
@PaulWoitaschek
Copy link
Contributor

To us, public API means anything that is not private.

It really depends where you set the boundaries. If I have an internal class which is used in the same module it still has a public api (what it exposes to other classes within the same gradle module).

@mlewandowskipt
Copy link
Author

mlewandowskipt commented Jan 2, 2024

Agree with @PaulWoitaschek here - in multi-module setup internal class/method is a public API within the module. @paul-dingemans can we reopen this issue and make the rule less strict, or configurable?

@paul-dingemans
Copy link
Collaborator

I do understand the way you look at it. But other devs with just reason differently, and refer to the strict meaning in the Kotlin Coding conventions.

As documented in #2345:

If we go this route, more exceptions will follow. The end result will be that properties can always start with an _. I think we should as close to the coding conventions as is possible. We can consider to split this rule and move cheking of the backing property to a separate rule, which then can be disabled if a project uses backing properties less strict than the coding conventions.

can we reopen this issue and make the rule less strict, or configurable?

I do not think this important enough to create a configuration option for. See https://pinterest.github.io/ktlint/latest/faq/#can-a-new-toggle-be-added-to-optionally-enabledisable-format-code-in-a-particular-way

@OscarSpruit
Copy link

The visibility modifier should not matter for this rule. Take this example from the official Android guidelines:

private var _binding: ResultProfileBinding? = null
// This property is only valid between onCreateView and
// onDestroyView.
private val binding get() = _binding!!

override fun onCreateView(...): View? {
    _binding = ResultProfileBinding.inflate(inflater, container, false)
    ...
}

override fun onDestroyView() {
    _binding = null
}

The backing field is made non-nullable with the other field during the lifecycle of this object. IMO this is a valid use case to improve quality of code in places that use this field and to improve overall developer experience.

@paul-dingemans could you reconsider this rule? Or at least can this rule be configurable for the Android folks?

@dharmeshrathore
Copy link

dharmeshrathore commented Apr 18, 2024

Hi @paul-dingemans

I am still getting following error on below code - "Backing property is only allowed when a matching property or function exists (standard:backing-property-naming)"

private var _binding: FragmentCheckoutBinding? = null
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

override fun onCreateView(...): View? {
    _binding = FragmentCheckoutBinding.inflate(inflater, container, false)
    ...
}

override fun onDestroyView() {
    _binding = null
}

I am using "org.jlleitschuh.gradle.ktlint:12.1.0" in my Android studio
and here is my ktlint block in my build.gradle.kts

ktlint {
    android.set(true)
    ignoreFailures.set(false)
    reporters {
        reporter(ReporterType.PLAIN)
        reporter(ReporterType.CHECKSTYLE)
    }
}

Help here to resolve this issue at my end ? and tell me what rule should is add in my .editorConfig to fix this issue ?

@paul-dingemans
Copy link
Collaborator

Please use Ktlint CLI if you want more information about the violation. In your example the problem is that the matching property is a private and therefore not qualifies as a backing property according to the style guides.

17:39:14.606 [main] INFO com.pinterest.ktlint.cli.internal.KtlintCommandLine -- Enable default patterns [**/*.kt, **/*.kts]
class Abgs {
    private var _binding: FragmentCheckoutBinding? = null
    // This property is only valid between onCreateView and
    // onDestroyView.
    private val binding get() = _binding!!

    override fun onCreateView(): View? {
        _binding = FragmentCheckoutBinding.inflate(inflater, container, false)
    }

    override fun onDestroyView() {
        _binding = null
    }
}

<stdin>:2:17: Backing property is only allowed when the matching property or function is public (standard:backing-property-naming)

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

No branches or pull requests

5 participants