From afb258fce735f22da94e7433ae5e470648439a1b Mon Sep 17 00:00:00 2001 From: vtchem Date: Fri, 13 Nov 2020 15:49:25 +0300 Subject: [PATCH 01/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-chapter-0.md | 53 +++++----- info/guide/guide-chapter-1.md | 105 +++++++++---------- info/guide/guide-chapter-2.md | 89 ++++++++-------- info/guide/guide-chapter-3.md | 186 +++++++++++++++++----------------- info/guide/guide-chapter-4.md | 43 ++++---- info/guide/guide-chapter-5.md | 60 ++++++----- info/guide/guide-chapter-6.md | 90 ++++++++-------- 7 files changed, 310 insertions(+), 316 deletions(-) diff --git a/info/guide/guide-chapter-0.md b/info/guide/guide-chapter-0.md index 82e2e5cf8a..af9ef9272f 100644 --- a/info/guide/guide-chapter-0.md +++ b/info/guide/guide-chapter-0.md @@ -2,7 +2,9 @@ ### 0.1 Purpose of this document -For code to be considered "good", it must entail the following characteristics: +The purpose of this document is to provide a specification that software developers could reference to enhance their ability to write consistent, easy-to-read, and high-quality code. +Such a specification will ultimately improve software development efficiency and product competitiveness. +For the code to be considered high-quality, it must entail the following characteristics: 1. Simplicity 2. Maintainability 3. Reliability @@ -11,55 +13,52 @@ For code to be considered "good", it must entail the following characteristics: 6. Portability 7. Reusability -Programming is a profession that involves creativity. -Software developers can reference this specification, which will enhance their ability to write consistent, easy-to-read, and high-quality code. -This will ultimately improve product competitiveness and software development efficiency. ### 0.2 General principles -As a very modern and advanced programming language (completely like other languages), Kotlin complies with the following general principles: -1. Clarity: Clarity is a necessary feature of programs that are easy to maintain and refactor. -2. Simplicity: Simple code is easy to understand and implement. -3. Consistency: Unification is particularly important when the same team works on the same project, utilizing similar styles. It enables code to be easily modified, reviewed, and understood by the team members. +Like other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles: +1. Clarity — a necessary feature of programs that are easy to maintain and refactor. +2. Simplicity — a code is easy to understand and implement. +3. Consistency — enables a code to be easily modified, reviewed and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles.enables code to be easily modified, reviewed and understood by the team members. -In addition, we need to consider the following factors when programming on Kotlin: +Also, we need to consider the following factors when programming on Kotlin: -1. Write clean and simple Kotlin code +1. Writing clean and simple Kotlin code Kotlin combines two of the main programming paradigms: functional and object-oriented. - Both of these paradigms are trusted, well-known software engineering practices. - As a young programming language, Kotlin builds on well-established languages such as Java, C++, C#, and Scala. - This is why Kotlin introduces many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example: type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar. + Both of these paradigms are trusted and well-known software engineering practices. + As a young programming language, Kotlin builds (???) on well-established languages such as Java, C++, C#, and Scala. + This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar. -2. Follow Kotlin idioms +2. Following Kotlin idioms - The author of Kotlin, Andrey Breslav, mentioned that it is both pragmatic and practical, but not academic. - Its pragmatic features enable ideas to easily be transformed into real working software. This programming language is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/). + The author of Kotlin, Andrey Breslav, mentioned that Kotlin is both pragmatic and practical, but not academic. + Its pragmatic features enable ideas to be transformed into real working software easily. Kotlin is closer to natural languages than its predecessors, and it implements the following design principles: readability, reusability, interoperability, security, and tool-friendliness (https://blog.jetbrains.com/kotlin/2018/10/kotlinconf-2018-announcements/). -3. Use Kotlin efficiently +3. Using Kotlin efficiently - Some Kotlin features help you write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract. + Some Kotlin features can help you to write higher-performance code: including rich coroutine library, sequences, inline functions/classes, arrays of basic types, tailRec, and CallsInPlace of contract. ### 0.3 Terminology -**Rules**: conventions that should be followed when programming. +**Rules** — conventions that should be followed when programming. -**Recommendations**: conventions that should be considered when programming. +**Recommendations** — conventions that should be considered when programming. -**Explanation**: necessary explanations of rules and recommendations. +**Explanation** — necessary explanations of rules and recommendations. -**Valid Example**: examples (recommended) of rules and recommendations. +**Valid Example** — recommended examples of rules and recommendations. -**Invalid Example**: examples (not recommended) of rules and recommendations. +**Invalid Example** — not recommended examples of rules and recommendations. Unless otherwise stated, this specification applies to versions 1.3 and later of Kotlin. ### 0.4 Exceptions -Even though exceptions may exist, it is important to understand why rules and recommendations are needed. -Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception leads to many and can completely destroy the consistency of code. As such, there should be very few exceptions. -When modifying open-source code or third-party code, you can choose to implement the style used by the code (as opposed to using the existing specifications) to maintain consistency. -Software that is directly based on the interface of the Android native operating system, such as the Android Framework, remains consistent with the Android style. +Even though exceptions may exist, it is essential to understand why rules and recommendations are needed. +Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. +When modifying open-source code or third-party code, you can choose to implement the code's style (???) used by the code (instead of using the existing specifications) to maintain consistency. +Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. \ No newline at end of file diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index f14659cfc7..027b532586 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -1,18 +1,20 @@ ## 1. Naming -In programming, it is difficult to meaningfully and appropriately name variables, functions, classes, etc. Good names clearly express the main ideas and functionality of your code, as well as avoid misinterpretation, unnecessary coding and decoding, magic numbers, and inappropriate abbreviations. +In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, magic numbers (???), and inappropriate abbreviations. -### Rule 1.0.1: file encoding format must be UTF-8 only -The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. +Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. -### 1.1 Identifiers naming -### Rule 1.1.1: Identifiers +### 1.1 Identifier names +### 1.1.1: Identifiers naming conventions +**Rule (???):** + +For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. Explanation: Each valid identifier name should match the regular expression `\w{2,64}`. `{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility. -Name lengths of less than 31 characters are generally recommended, but this depends on the project. Otherwise, class declaration with generics or inheritance from a super class can cause line breaking for example. No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. +Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking, for example (???). No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. -2. For files, choose names that describe their content. Use camel case (PascalCase) and `.kt` extension. +2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension. 3. Typical examples of naming: @@ -30,14 +32,13 @@ Name lengths of less than 31 characters are generally recommended, but this depe val `my dummy name-with-minus` = "value" ``` -The only exception is function names in `Unit tests`. +The only exception is function names in `Unit tests.` 5. Backticks (``) should not be used for identifiers, except the names of test methods (marked with @Test annotation): ```kotlin @Test fun `my test`() { /*...*/ } ``` -6. The following table contains some characters that cause confusion. Be careful when using them as identifiers, or use other names instead. - +6. The following table contains some characters that may cause confusion. Be careful when using them as identifiers. To avoid issues, use other names instead. | Expected | Confusing name | Suggested name | | ------------- | ------------------------ | ---------------- | | 0 (zero) | O, D | obj, dgt | @@ -50,29 +51,31 @@ The only exception is function names in `Unit tests`. | rn, m | m,rn | mbr, item | **Exceptions** -- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for for such variables. +- The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables. - The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}` -- The Java community generally does not recommend the use of prefixes; however, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively. -Note that prefixing can also negatively affect the style, as well as the auto generation of getters and setters. +- The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively. +Note that prefixing can also negatively affect the style and the auto-generation of getters and setters. | Type | Naming style | | ---- | ---- | -| Interfaces, classes, annotations, enumerated types, and object type names | Camel case starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. | -| Class fields, local variables, methods, and method parameters | Camel case starting with a small letter. Test methods may be underlined with '_'., the only exception is [backing properties](#r6.1.7) +| Interfaces, classes, annotations, enumerated types, and object type names | Camel case, starting with a capital letter. Test classes have a Test suffix. The filename is 'TopClassName'.kt. | +| Class fields, local variables, methods, and method parameters | Camel case starting with a low case letter. Test methods can be underlined with '_'; the only exception is [backing properties](#r6.1.7). | Static constants and enumerated values | Only uppercase underlined with '_' | | Generic type variable | Single capital letter, which can be followed by a number, for example: `E, T, U, X, T2` | | Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`| ### 1.2 Packages names -### Rule 1.2.1: Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain`, and numbers are permitted in package names. -Package names are all written in lowercase, and consecutive words are simply concatenated together (no underscores). Package names should contain both the product and module names, as well as the department or team name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. +### Rule 1.2.1: Package names dots +Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. +Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product and module names, and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. **Exceptions:** -- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain`.- In some cases, if the package name starts with a number or other characters, but these characters cannot be used at the beginning of the Java/Kotlin package name, or the package name contains reserved Java keywords, underscores are allowed. -- Underscores are sometimes permitted if the package name starts with a number or other character, which cannot be used at the beginning of the Java/Kotlin package name; or the package name contains reserved Java keywords. For example: org.example.hyphenated_name, int_.example, com.example._123name -For example: `org.example.hyphenated_name`,` int_.example`, `com.example._123name` +- In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.` +- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name or the package name contains reserved Java keywords, underscores are allowed. (???) +- Underscores are sometimes permitted if the package name contains reserved Java keywords, such as org.example.hyphenated_name, int_.example, com.example._123name +Examples: `org.example.hyphenated_name`,` int_.example`, `com.example._123name` **Valid example**: ```kotlin @@ -81,12 +84,13 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces -### Rule 1.3.1: Classes, enumerations, interface names use camel case nomenclature -1. The class name is usually a noun or a noun phrase using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. -The name of an interface can also be a noun or noun phrase (such as `List`), or an adjective or adjective phrase (such as `Readable`). -Note that verbs should not be used to name classes; however, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid vague words like Manager and Process. +### Rule 1.3.1: Classes, enumerations, interface names use Camel case +Classes, enumerations, and interface names use camel case nomenclature (???). Follow the naming rules described below: +1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. +An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`). +Note that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`. -2. Test classes start with the name of the class they are testing and end with Test. For example: HashTest or HashIntegrationTest +2. Test classes start with the name of the class they are testing and end with 'Test'. For example, `HashTest` or `HashIntegrationTest`. **Invalid example**: ```kotlin @@ -106,19 +110,19 @@ class Order {} ### 1.4 Functions -### Rule 1.4.1: function names should be in camel case - -1. Function names are usually verbs or verb phrases, and use the camel case nomenclature (`lowerCamelCase`). +### Rule 1.4.1: Function names should be in camel case (???) +Function names should be in camel (???) case. Follow the naming rules described below: +1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. -The format is as follows: +To name functions use the following formatting rules: -a) To get, modify, or calculate a certain value: get + non-boolean field(). However, note that getters are automatically generated by the Kotlin compiler for some classes, and the special get syntax is preferred for fields: kotlin private val field: String get() { }. +a) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }. ```kotlin private val field: String get() { } ``` -Additionally, calling property access syntax is preferred to calling getter directly. (In this case, the Kotlin compiler will automatically call the corresponding getter). +Note: The calling property access syntax is preferred to call getter directly. In this case, the Kotlin compiler automatically calls the corresponding getter. b) `is` + boolean variable name() @@ -127,11 +131,11 @@ c) `set` + field/attribute name(). However, note that the syntax and code genera d) `has` + Noun / adjective () e) verb() -The verb is mainly used on the object of the action itself, such as `document.print ()` +Note: Note: Verb are primarily used for the action objects, such as `document.print ()` f) verb + noun() -g) The Callback function allows for names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`. +g) The Callback function allows the names that use the preposition + verb format, such as: `onCreate()`, `onDestroy()`, `toString()`. **Invalid example**: @@ -153,22 +157,21 @@ fun draw() fun addKeyListener(Listener) ``` -2. An underscore can be included in the JUnit test function name, and should be a logical component used to separate names. Each logical part is written in lowerCamelCase. For example: a typical pattern _, such as pop_emptyStack - +2. An underscore can be included in the JUnit test function name and should be a logical component used to separate names (???). Each logical part denoted in lowerCamelCase (???), for example, a typical pattern of using underscore: pop_emptyStack. -### 1.5 Constants -### Rule 1.5.1 Constant names should be in UPPER case, words separated by underscore - -1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. +### 1.5 Constants +### Rule 1.5.1 Constant names should be in UPPER case, words separated by underscore (???) +Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: +1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. -2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. +2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. 3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. -4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. +4. Use meaningful constants instead of `magic numbers` (???). SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. -Typically, these constants represent business logic values like measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. -Magic numbers can be avoided through the following methods: +These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. +You can avoid using magic numbers with the following method: - Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`. - Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9) @@ -188,12 +191,12 @@ const val String APPLICATION_NAME = "Launcher"; ### 1.6 Non-constant fields (variables) -### Rule 1.6.1: The name of the non-constant field should use camel case and start with a lowercase letter. - -A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. The name of variables with a type from collections (sets, lists, etc.) should contain plural nouns. +### Rule 1.6.1: Non-constant field name +Non-constant field names should use camel case and start with a lowercase letter. +A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. For example: `var namesList: List` -Names of non-constant variables should use lower camel case. The name of the final immutable field used to store the singleton object can use the same notation with camel case. +Names of non-constant variables should use lower camel case (???). The name of the final immutable field used to store the singleton object can use the same camel case notation. **Invalid example**: ```kotlin @@ -208,13 +211,13 @@ val users: List = listOf(); val mutableCollection: MutableSet = HashSet() ``` -### Recommendation 1.6.2: Avoid using Boolean variable names with negative meaning. +### Rule 1.6.2: Boolean variable names with negative meaning -*Note*: When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". +Avoid using Boolean variable names with negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". For instance, it is not easy to understand the meaning of !isNotError. The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes. -However, methods that return Boolean type do not all have this notation. -For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (which is commonly used by JavaBeans), or has, can, should, must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even easier as everything is on the byte-code level under the hood. +However, not all methods returning Boolean type have this notation. +For Boolean local variables or methods, it is highly recommended that you add non-meaningful prefixes, including is (commonly used by JavaBeans), has, can, should, and must. Modern integrated development environments (IDEs) such as Intellij are already capable of doing this for you when you generate getters in Java. For Kotlin, this process is even more straightforward as everything is on the byte-code level under the hood. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index bd7ef66917..3b4090dc16 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -1,12 +1,12 @@ ## 2. Comments -The best practice involves beginning your code with a short summary, which can be one sentence. -You should balance between writing no comments at all and obvious comments for each line of code. +The best practice is to begin your code with a summary, which can be one sentence. +Try to balance between writing no comments at all and obvious commentary statements for each line of code. Comments should be accurately and clearly expressed, without repeating the name of the class, interface, or method. -Comments are not a solution to bad code. Instead, you should fix the code as soon as you notice an issue, or plan to fix it (with a TODO comment including a Jira number). -Comments should accurately reflect the design ideas and logic of the code, and then describe the code's business logic. +Comments are not a solution to the wrong code. Instead, you should fix the code as soon as you notice an issue or plan to fix it (by entering a TODO comment, including a Jira number). +Comments should accurately reflect the code's design ideas and logic and further describe its business logic. As a result, other programmers will be able to save time when trying to understand the code. -Imagine that you are writing the comments to help your future self understand the original ideas behind the code. +Imagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future. ### 2.1 General form of Kdoc @@ -28,7 +28,7 @@ It is also shown in the following single-line form: ```kotlin /** Short form of KDoc. */ ``` -When the entire KDoc block can be stored in one line (and there is no KDoc mark @XXX), a single-line form can be used. For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html). +Use a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html). ### Rule 2.1.1: KDoc is used for each public, protected or internal code element @@ -36,10 +36,9 @@ At a minimum, KDoc should be used for every public, protected, or internal decor Exceptions: -1. For setters/getters of properties obvious comments are optional. - (Note that simple `get/set` methods are generated by Kotlin under the hood). For example, getFoo can also be `return foo`. +1. For setters/getters of properties, obvious comments are optional (???). Note that Kotlin generates simple `get/set` methods under the hood). For example, getFoo can also be `return foo`. -2. It is optional to add comments for simple one-line methods like: +2. It is optional to add comments for simple one-line methods, such as shown in the example below: ```kotlin val isEmpty: Boolean get() = this.size == 0 @@ -51,9 +50,9 @@ or fun isEmptyList(list: List) = list.size == 0 ``` -3. You can skip KDocs for a method's override if the method is almost like the super class method. - -### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc. +Note: You can skip KDocs for a method's override if it is almost the same as the superclass method. +### Rule 2.1.2: Describing methods with arguments, return value or can throw exceptions +When the method has arguments, return value, or can throw exceptions, it must be described in the KDoc block: with @param, @return, @throws **Valid examples**: @@ -89,27 +88,29 @@ fun isEmptyList(list: List) = list.size == 0 } ``` -### Rule 2.1.3: There is only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws +### Rule 2.1.3: Only one space between the Kdoc tag and content. Tags are arranged in the order. +There should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws. -This is how Kdoc should look like and what it should contain: +Therefore, Kdoc should contain the following: - Functional and technical description, explaining the principles, intentions, contracts, API, etc. - The function description and @tags (`implSpec`, `apiNote`, and `implNote`) require an empty line after them. - `@implSpec`: A specification related to API implementation, and it should let the implementer decide whether to override it. -- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread safe, as well as the algorithm complexity, input and output range, exceptions, etc. +- `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc. - `@implNote`: A note related to API implementation, which implementers should keep in mind. -- Then one empty line, followed by regular `@param`, `@return`, `@throws` and other comments. -- The conventional standard "block labels" are arranged in order: `@param`, `@return`, `@throws`. -- Empty descriptions in tag blocks are not permitted. It is better not to write Kdoc than to waste code line on empty space. +- One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments. +- The conventional standard "block labels" arranged in the following order: `@param`, `@return`, `@throws`. +Kdoc should not contain: +- Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space. - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). -- (!) KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. +Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. -If a tag block cannot be described in one line, you should indent the content of the new line by `4 spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). +If a tag block cannot be described in one line, you should indent the content of the new line by `4 spaces` (???) from the `@` position to achieve alignment (`@` counts as one + three spaces). -**Exception:** When the descriptive text in a tag block is too long to wrap, the alignment can be indented with the descriptive text in the previous line. The descriptive text of multiple tags does not need to be aligned. +**Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. See [3.8 Horizontal space](#c3.8). -In Kotlin compared to Java you are able to put several classes inside one file so each class should have a Kdoc formatted comment (this is also stated in rule 2.1). -This comment should contain @since tag. The good style is to write the version of the application when functionality was released. It should be written after a `@since` tag. +In Kotlin, compared to Java, you are able to put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). +This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag. **Examples:** @@ -134,13 +135,13 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo ### 2.2 Comments to the file header ### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. -Comments on the file header should be stored before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format. +Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format. The following examples for Huawei describe the format of the **copyright license**: \ Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \ English version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.` -Regarding the **release notes**, see examples below: +Regarding the **release notes**, see examples below (???): - `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. These two years can be the same (for example, `2020–2020`). When the file is substantially changed (for example, through feature extensions and major refactorings), the subsequent years must be updated. @@ -159,28 +160,28 @@ The following example is a copyright statement for Huawei, without other functio ``` The following factors should be considered when writing the file header or comments for top-level classes: -- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, class declaration should start immediately without using a newline. -- Maintain a unified format. The specific format can be formulated by the project (for example, in opensource) and you need to follow it. +- File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline. +- Maintain a unified format. The specific format can be formulated (???) by the project (for example, in opensource), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. -- Do not include empty comment blocks. As described in the preceding example, if there is no content after the option `@apiNote`, the entire tag block should be deleted. -- The industry does not include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). As such, it is not recommended to include historical data in the comments of the Kotlin source code. +- Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted. +- The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. ### 2.3 Comments on the function header -### Rule 2.3.1: Do not use or make unnecessary and useless comments. +### Rule 2.3.1: Do not make unnecessary and useless comments. Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding [KDoc](#c2.1) style rules. -In Chapter 1 of the current code style, we stated that the function name should self-comment its functionality as much as possible. Therefore, in the Kdoc, try to mention things that are not stored in the function name. +As stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name. Avoid unnecessary comments on dummy coding. -The content of the function header comment is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc. -The module's external interface declaration and its comments should clearly convey important and useful information. +The function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc. ### 2.4 Code comments -### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. There must be one space between the comment's character and content. There must be a newline between a Kdoc and the preceding code. - -- There must be one space between the comment character and the content of the comment; there must be a newline between a Kdoc and the previous code above. -An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). +### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. +It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: +- There must be one space between the comment character and the content of the comment +- There must be a newline (???) between a Kdoc and the pressiding code +- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** ```kotlin @@ -222,7 +223,7 @@ An empty line should not exist between a Kdoc and the code it is describing. You ``` - Leave one single space between the comment on the right side of the code and the code. -Conditional comments in the `if-else-if` scenario: To help other programmers understand the code, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. +If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes your code more understandable. When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces. Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`. @@ -257,16 +258,16 @@ val someVal = if (nr % 15 == 0) { val x = 0 // this is a comment ``` -### Rule 2.4.2: Do not comment unused code blocks (including imports). Delete these code blocks immediately. - -Code is not used to store history. git, svn, or other VCS tools should be used for this purpose. +### Rule 2.4.2: Do not comment on unused code blocks +Do not comment on unused code blocks, including imports. Delete these code blocks immediately. +A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose. Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be properly maintained. When you attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed. The correct approach is to delete the unnecessary code directly and immediately when it is not used. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -### Recommendation 2.4.3: Code formally delivered to the client typically should not contain TODO/FIXME comments. - +### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. +The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. They should all have a unified style to facilitate the unified text search processing. @@ -276,4 +277,4 @@ They should all have a unified style to facilitate the unified text search proce // FIXME: Jira-XXX - fix NPE in this code block ``` -In the version development stage, these annotations can be used to highlight the issues in code, but all of them should be fixed before a new product version is released. +At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released. \ No newline at end of file diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index b2d4ae4f29..dba9485fc7 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -3,14 +3,13 @@ ### 3.1 File-related rules ### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines). -If the file is too long, it is probably complex and can therefore be split into smaller files, functions, or modules. -It is recommended that you horizontally or vertically split the file according to responsibilities or hierarchy, respectively. -Code generation is the only exception to this. -Auto-generated files that are not manually modified can be longer. +If the file is too long and complex, it should be split into smaller files, functions, or modules. +It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy, respectively (???). The only exception to this rule is code generation. (???) +The auto-generated files that are not manually modified can be longer -### Rule 3.1.2: A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. - -a) They should be in the following order: +### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. +A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. +a) Code blocks should be in the following order: 1. Kdoc for licensed or copyrighted files 2. `@file` annotation 3. Package name @@ -24,7 +23,7 @@ c) Import statements are alphabetically arranged, without using line breaks and d) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename -### Recommendation 3.1.3: Import statements should appear in the following order: Android, internal company imports, external imports, java core dependencies, and Kotlin standard library. Each group should be separated by a blank line. +### Recommendation 3.1.3: Import statements order. From top to bottom, the order is the following: 1. Android @@ -33,7 +32,7 @@ From top to bottom, the order is the following: 4. Java core packages 5. kotlin stdlib -Each category should be alphabetically arranged. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements). +Each category should be alphabetically arranged. Each group should be separated by a blank line. This style is compatible with [Android import order](https://source.android.com/setup/contribute/code-style#order-import-statements). **Valid example**: ```kotlin @@ -54,9 +53,9 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -### Recommendation 3.1.4: The declaration part of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Their declaration should be separated by blank lines. - -Note: +### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. +The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. +Notes: 1. There should be no blank lines between properties. **Exceptions**: When there is a comment before a property on a separate line or annotations on a separate line. 2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc. @@ -69,7 +68,7 @@ The declaration part of a class or interface should be in the following order: - Init-blocks - Constructors - Methods or nested classes. Put nested classes next to the code they are used by. -If the classes are meant to be used externally and are not referenced inside the class, put them at the end after the companion object. +If the classes are meant to be used externally and are not referenced inside the class, put them after the companion object. - Companion object **Exception:** @@ -79,7 +78,7 @@ All variants of a `(private) val` logger should be placed in the beginning of th ### 3.2 Braces ### Rule 3.2.1: Braces must be used in conditional statements and loop blocks. -In `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement, braces should be used. In special Kotlin when statements, you do not need to use braces for statements with one line. +Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for statements with one line (???). **Valid example:** @@ -92,7 +91,7 @@ when (node.elementType) { CLASS -> checkClassElements(node) } ``` -**Exception:** The only exception is ternary operator in Kotlin (it is a single line `if () <> else <>` ) +**Exception:** The only exception is ternary operator in Kotlin (a single line `if () <> else <>` ) **Invalid example:** @@ -119,7 +118,7 @@ if (condition) { ### Rule 3.2.2 For *non-empty* blocks and block structures, the opening brace is placed at the end of the line -The K&R style (1TBS or OTBS) should be followed for *non-empty* code blocks with braces: +Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces: - The opening brace and first line of the code block are on the same line. - The closing brace is on its own new line. - The closing brace can be followed by a newline. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords. @@ -178,18 +177,18 @@ do { ### 3.3 Indentation ### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces. -Only spaces are permitted for indentation, and each indentation should equal `4 spaces` (tabs are not permitted). +Only spaces are permitted for indentation, and each indentation should equal `4 spaces` (tabs are not permitted) (???). If you prefer using tabs, simply configure them to automatically change to spaces in your IDE. -These code blocks should be indented if they are placed on the new line and the following conditions are met: -- The code block is placed immediately after an opening brace. -- The code block is placed after each operator, including assignment operator (`+`/`-`/`&&`/`=`/etc.). +These code blocks should be indented if they are placed on the new line, and the following conditions are met: +- The code block is placed immediately after an opening brace +- The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.) - The code block is a call chain of methods: ```kotlin someObject .map() .filter() ``` -- The code block is placed immediately the opening parenthesis. +- The code block is placed immediately after the opening parenthesis. - The code block is placed immediately after an arrow in lambda: ```kotlin @@ -208,10 +207,10 @@ b) Arguments in argument lists can be aligned if they are on different lines. 3. Eight spaces are used for functional-like styles when the newline is placed before the dot. 4. Super type lists: \ -a) Four spaces are used if the colon before the super type list is on a new line. \ -b) Four spaces are used before each super type, and eight are used if the colon is on a new line. +a) Four spaces are used if the colon before the supertype list is on a new line. \ +b) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line. -**Note:** there should be an indentation after all statements such as `if`, `for`, etc.; however, according to this code style, such statements require braces. +**Note:** there should be an indentation after all statements such as `if`, `for`, etc. However, according to this code style, such statements require braces. ```kotlin if (condition) @@ -219,7 +218,7 @@ if (condition) ``` **Exceptions**: -- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. Or a parameter that was moved to a new line can be on the same level as the previous argument: +- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces` (???). A parameter that was moved to a new line can be on the same level as the previous argument: ```kotlin fun visit( @@ -231,14 +230,14 @@ fun visit( } ``` -- Operators like `+`/`-`/`*`/e.t.c can be indented with `8 spaces`: +- Such operators as `+`/`-`/`*` can be indented with `8 spaces`: ```kotlin val abcdef = "my splitted" + " string" ``` -- List of super types should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if leading colon is also on a separate line +- A list of supertypes should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if the leading colon is also on a separate line ```kotlin class A : @@ -251,14 +250,12 @@ class A ### 3.4 Empty blocks -### Recommendation 3.4.1: Try to avoid empty blocks, and ensure braces start on a new line. - -An empty code block can be closed immediately on the same line, and on the next line. However, a newline is recommended between opening and closing braces `{}`. -(See the examples below.) +### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. -**Generally, empty code blocks are prohibited** and are very bad practice (especially for catch block). -They are only appropriate for overridden functions, when the functionality of the base class is not needed in the class-inheritor. +An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.) +Generally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block). +They are only appropriate for overridden functions when the base class's functionality is not needed in the class-inheritor. ```kotlin override fun foo() { } @@ -280,7 +277,7 @@ try { } catch (e: Some) {} ``` -Use this valid code instead: +Use the following valid code instead: ```kotlin try { doSomething() @@ -292,11 +289,11 @@ try { ### 3.5 Line length ### Recommendation 3.5.1: Line length should be less than 120 symbols. -This international code style prohibits `non-Latin` (`non-ASCII`) symbols. +The international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: - One wide character occupies the width of two narrow characters. -The "wide" and "narrow" part of a character are defined by its [east asian width Unicode attribute](https://unicode.org/reports/tr11/). +The "wide" and "narrow" parts of a character are defined by (???) its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/). Typically, narrow characters are also called "half-width" characters. All characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters. Wide characters are also called "full-width" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`,` , `;` ), full-width letters and numbers (such as `A、3`) are "full-width" characters. @@ -306,14 +303,14 @@ Each one of these characters represents two narrow characters. **Exceptions:** -1. The long URL or long JSON method reference in KDoc -2. The `package` and `import` statements -3. The command line in the comment, enabling it to be cut and pasted into the shell for use +1. The long URL or long JSON method reference in KDoc. +2. The `package` and `import` statements. +3. The command line in the comment, enabling it to be cut and pasted into the shell for use. ### 3.6 Line breaks (newlines) ### Recommendation 3.6.1: Each line can have a maximum of one statement. -Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;`, because it worsens code visibility. +Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** ```kotlin @@ -328,13 +325,13 @@ val b = "" ### Rule 3.6.2: Rules for line-breaking -1) Compared to Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline. - There should be no redundant semicolon at the end of lines. +1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline. + There should be no redundant semicolon at the end of the lines. -When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). +When a newline (???) is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`. -Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not be split. +Note that all comparison operators, such as `==`, `>`, `<`, should not be split. **Invalid example**: ```kotlin @@ -349,7 +346,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b } ``` -**Note**, that you need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call: +**Note:** You need to follow the functional style, meaning each function call in a chain with `.` should start at a new line if the chain of functions contains more than one call: ```kotlin val value = otherValue!! .map { x -> x } @@ -359,7 +356,7 @@ Note that all operators for comparing such as `==`, `>`, `<`, e.t.c should not b } .size ``` -**Note**, that parser prohibits the separation of operator `!!` from the value it is checking. +**Note:** The parser prohibits the separation of the `!!` operator from the value it is checking. **Exception**: If a functional chain is used inside the branches of a ternary operator, it does not need to be split with newlines. @@ -373,8 +370,8 @@ if (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1) A brace should be placed immediately after the name without any spaces in declarations or at call sites. 4) Newlines should be placed right after the comma (`,`). 5) If a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters. - If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`). - See the following examples. + If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`). + The following examples illustrate this rule: **Invalid example:** @@ -394,8 +391,8 @@ value.map { name -> val someValue = { node:String -> node } ``` -6) When the function contains only a single expression, it can be expressed as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions). - The following style should not be used. +6) When the function contains only a single expression, it can be expressed (???) as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions). + The below example shows the style that should not be used. Instead of: ```kotlin @@ -441,7 +438,7 @@ fun foo( } ``` -8) If super type list has more than 2 elements, they should be separated by newlines. +8) If the supertype list has more than two elements, they should be separated by newlines **Valid example:** ```kotlin @@ -455,9 +452,8 @@ class MyFavouriteVeryLongClassHolder : ### 3.7 Blank lines ### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size -By reducing unnecessary blank lines, you can display more code on one screen, which in turn improves code readability. - -- Blank lines should separate content based on relevance, and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). +By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. +- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). - Do not use more than one line inside methods, type definitions, and initialization expressions. - Generally, do not use more than two consecutive blank lines in a row. - Do not put newlines in the beginning or end of code blocks with curly braces. @@ -476,12 +472,12 @@ fun baz() { ### 3.8 Horizontal space ### Rule 3.8.1: Usage of whitespace for code separation -**Note:** This recommendation corresponds to cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. (This logic is described in another rule.) +**Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.) -1. All keywords (such as `if`, `when`, and `for`) should be separated with a single whitespace from the opening parenthesis. +1. Separate all (???) keywords (such as `if`, `when`, and `for`) from the opening parenthesis with single whitespace. The only exception is the `constructor` keyword, which should not be separated. -2. Separate all keywords (such as `else` or `try`) from the opening brace (`{`) with a single whitespace. +2. Separate all keywords (???) (such as `else` or `try`) from the opening brace (`{`) with a single whitespace. If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()` 3. Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses: @@ -502,15 +498,15 @@ fun baz() { `Object::toString` - The dot separator (`.`) that stays on the same line with an object name:\ `object.toString()` -- Safe access modifiers: `?.` and `!!`, that stay on the same line with an object name:\ +- Safe access modifiers `?.` and `!!` that stay on the same line with an object name:\ `object?.toString()` - Operator `..` for creating ranges:\ `1..100` -5. Spaces should be used after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line. +5. Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line. However, note that this code style prohibits the use of (`;`) in the middle of a line ([Rule 3.2.2](#r3.2.2)). There should be no whitespaces at the end of a line. - The only scenario where there should be no space after a colon is when the colon is used in annotation to specify a use-site target (for example, `@param:JsonProperty`). + The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`). There should be no spaces before `,` , `:` and `;`. **Exceptions** for spaces and colons are the following: @@ -528,13 +524,13 @@ fun baz() { } ``` -6. There should be *only one space* between identifier and it's type: `list: List` -If the type is nullable there should be no space before `?`. +6. There should be *only one space* between the identifier and it's type: `list: List` +If the type is nullable, there should be no space before `?`. 7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`. 8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis: - `foo() {}`. Note that this sub-rule is related only to spaces, the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2). + `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2). This rule does not prohibit, for example, the following code: ```kotlin fun foo @@ -543,19 +539,19 @@ fun foo ) ``` -9. Never put a space after `(`, `[`, `<` (when used as bracket in templates) or before `)`, `]`, `>` (when used as bracket in templates). +9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates). -10. There should be no spaces between prefix/postfix operator (like `!!` or `++`) and it's operand. +10. There should be no spaces between prefix/postfix operator (like `!!` or `++`), and it's an operand. ### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. -*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used, becuase: +*Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because: -- When modifying code, it takes a lot of time for new developers to format, support, and fix alignment issues. +- When modifying code, it takes much time for new developers to format, support, and fix alignment issues. - Long identifier names will break the alignment and lead to less presentable code. - Alignment possesses more disadvantages than advantages. To reduce maintenance costs, misalignment is the best choice. -Recommendation: Alignment only looks good for `enum class`, where it can be used in table format to improve code readability: +Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability: ```kotlin enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule { PACKAGE_NAME_MISSING (1, true, "no package name declared in a file"), @@ -580,7 +576,7 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean ### 3.9 Enumerations ### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. -1) Enum values are separated by comma and a line break. `;` is put on the new line: +1) Enum values are separated by a comma and a line break. `;` is put on the new line: ```kotlin enum class Warnings { A, @@ -590,28 +586,28 @@ enum class Warnings { } ``` -This will help resolve conflicts and reduce the value's number during merging pull requests. +This will help resolve conflicts and reduce the value's number (???) during merging pull requests. Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma). -2) If the enum is simple (no properties, methods, and comments inside), it can be declared in a single line: +2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line: ```kotlin enum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS } ``` -3) Enum classes take preference if possible, for example, instead of two Boolean properties like: +3) Enum classes take preference if possible (???), for example, instead of two Boolean properties, such as shown below: ```kotlin val isCelsius = true val isFahrenheit = false ``` -use enum class: +Using enum class: ```kotlin enum class TemperatureScale { CELSIUS, FAHRENHEIT } ``` - The variable value only changes within a fixed range and is defined with the enum type. -- Avoid comparison with magic numbers of `-1, 0, and 1`, instead of this use enums: +- Avoid comparison with magic numbers of `-1, 0, and 1`; use enums instead. ```kotlin enum class ComparisonResult { @@ -626,31 +622,31 @@ enum class ComparisonResult { ### 3.10 Variable declaration ### Rule 3.10.1: Declare one variable per line. -Each property or variable declaration must be declared on a separate line. +Each property or variable must be declared on a separate line. **Invalid example**: ```kotlin val n1: Int; val n2: Int ``` -### Recommendation 3.10.2: Variables should be declared close to the line where they are first used. -To minimize their scope, local variables should be declared close to the point where they are first used. This will also increase readability of the code. -Local variables are usually initialized during declaration or initialized immediately after. -The member fields of the class should be declared collectively (see [Rule 3.1.2](#s3.1.2) for details on class structure). +### Recommendation 3.10.2: Variables should be declared near the line where they are first used. +Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. +Local variables are usually initialized during their declaration or immediately after. +The member fields of the class should be declared collectively (see [Rule 3.1.2](#s3.1.2) for details on the class structure). ### 3.11 When expression -### Rule 3.11.1: 'when' statements must have an 'else' branch, unless the condition variable is enumerated or a sealed type. -Each `when` statement contains an `else` statement group, even if it does not contain any code. +### Rule 3.11.1: The 'when' statement must have an 'else' branch unless the condition variable is enumerated or a sealed type. +Each `when` statement should contain an `else` statement group, even if it does not contain any code. -**Exception:** If a when statement of type `enum or sealed` contains all values of a enum - there is no need to have "else" branch. +**Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an "else" branch. The compiler can issue a warning when it is missing. ### 3.12 Annotations ### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. -1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). +1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line). **Valid example**: ```kotlin @@ -666,7 +662,7 @@ fun getNameIfPresent() { /* ... */ } @CustomAnnotation class Foo {} ``` -3. 3. Multiple annotations applied to a field or property can appear on the same line as the field. +3. Multiple annotations applied to a field or property can appear on the same line as the corresponding field. **Valid example**: ```kotlin @@ -675,9 +671,9 @@ fun getNameIfPresent() { /* ... */ } ### 3.13 Layout of comments -### Recommendation 3.13.1: Block comments are at the same indentation level as the surrounding code. +### Recommendation 3.13.1: Block comments location. -Block comments are at the same indentation level as the surrounding code. See examples below. +Block comments should be placed at the same indentation level as the surrounding code. See examples below. **Valid example**: @@ -695,7 +691,7 @@ class SomeClass { ### 3.14 Modifiers and constant values -### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow proper sequence. +### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. **Valid sequence:** ```kotlin @@ -720,9 +716,8 @@ operator data ``` -### Recommendation 3.14.2: Long numerical values should be separated by an underscore. - -**Note:** Underscores make it easier to read and find errors in numeric constants. +### Recommendation 3.14.2: An underscore should separate long numerical values. +**Note:** Using underscores simplifies reading and helps to find errors in numeric constants. ```kotlin val oneMillion = 1_000_000 val creditCardNumber = 1234_5678_9012_3456L @@ -733,8 +728,8 @@ val bytes = 0b11010010_01101001_10010100_10010010 ### 3.15 Strings -### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. Use raw strings and string templates instead. -Kotlin has significantly improved the use of Strings: +### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. +String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: [String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) As such, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines and you do not need to split them with newlines. @@ -751,9 +746,9 @@ val value = "$myStr concatenated" ``` ### Rule 3.15.2: String template format -**Redundant curly braces in string templates.** +**Redundant curly braces in string templates** -In case string template contains only one variable, - there is no need to use string template. Use this variable directly. +If there is only one variable in a string template, there is no need to use such a template. Use this variable directly. **Invalid example**: ```kotlin val someString = "${myArgument} ${myArgument.foo()}" @@ -764,7 +759,8 @@ val someString = "${myArgument} ${myArgument.foo()}" val someString = "$myArgument ${myArgument.foo()}" ``` -**Redundant string template.** +**Redundant string template** + In case string template contains only one variable - there is no need to use string template. Use this variable directly. **Invalid example**: diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index e2de4d5321..82937829e4 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -3,34 +3,33 @@ ### 4.1 Variables ### Rule 4.1.1: Do not use Float and Double types when accurate calculations are needed. Floating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases. -Binary floating-point numbers are unsuitable for precise calculations, because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length. +Binary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length. -The following example seems to be simple code that is obvious: +The following code example seems to be obvious: ```kotlin val myValue = 2.0 - 1.1 println(myValue) ``` -However, it will print a value such as: `0.8999999999999999` +However, it will print the following value: `0.8999999999999999` -As such, if you need to make precise calculations (for example, when dealing with currency, finance, or an exact science), `Int`, `Long`, `BigDecimal`, etc. are recommended. -Among them, `BigDecimal` should serve as a good choice. +Therefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended. +The `BigDecimal` type should serve as a good choice. **Invalid example:** \ -If a float value contains more than six to seven decimal numbers, it will be rounded off. +Float values containing more than six or seven decimal numbers will be rounded. ```kotlin val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817 ``` -**Valid example** (when accurate calculations are needed): +**Valid example** (when precise calculations are needed): ```kotlin val income = BigDecimal("2.0") val expense = BigDecimal("1.1") println(income.subtract(expense)) // you will obtain 0.9 here ``` -### Rule 4.1.2: The numbers of a float type should not be directly compared with the equality operator (==) or other methods like compareTo and equals. - +### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like compareTo and equals (???). Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems. **Invalid example**: @@ -67,9 +66,9 @@ if (abs(foo - bar) > 1e-6f) { ### Rule 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]. Variables with the `val` modifier are immutable (read-only). -Code robustness and readability increase through the use of such variables, as opposed to `var` variables. -This is because var variables can be reassigned several times in the business logic. -Of course, in some scenarios with loops or accumulators, only `var`s are permitted. +Code robustness and readability increase when using `val` variables instead of `var` variables. +This is because `var` variables can be reassigned several times in the business logic. +However, in some scenarios with loops or accumulators, only `var`s are permitted. ### 4.2 Types @@ -104,7 +103,7 @@ fun bar(x: String?) { } ``` -Smart cast and contracts are better because they reduce boilerplate code and forced type conversion. +Smart cast and contracts are a better choice because they reduce boilerplate code and features forced type conversion. **Invalid example**: ```kotlin @@ -122,12 +121,12 @@ fun foo(s: String?) { } ``` -### Recommendation 4.2.2: Try to use type alias to represent types and make code more readable. +### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. Type aliases provide alternative names for existing types. -If the type name is too long, you can replace it with a shorter name. It helps to shorten long generic types. +If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. For example, code looks much more readable if you introduce a `typealias` instead of a long chain of nested generic types. -We recommend the use of a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**. +We recommend using a `typealias` if the type contains **more than two** nested generic types and is longer than **25 chars**. **Invalid example**: ```kotlin @@ -152,7 +151,7 @@ typealias Predicate = (T) -> Boolean Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. ### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. -To avoid `NullPointerException` and help compiler checks prevent NPE, try to avoid using nullable types (with `?` symbol). +To avoid `NullPointerException` and help compiler checks prevent NPE (???) avoid using nullable types (with `?` symbol). **Invalid example**: ```kotlin @@ -165,8 +164,8 @@ val a: Int = 0 ``` Nevertheless, if you use Java libraries extensively, you will have to use nullable types and enrich your code with `!!` and `?` symbols. -Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)) avoid using nullable types. -Try to use initializers for empty collections. ), and try using initializers for empty collections. For example: If you want to initialize a list instead of using `null` use `emptyList()`. +Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)). +Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null` use `emptyList()`. **Invalid example**: ```kotlin @@ -179,14 +178,14 @@ val a: List = emptyList() ``` ### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. -As in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: +Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: ```kotlin val myVariable: Map = emptyMap() ``` -However, the compiler can inherit type parameters from the right value, and as such, will not force users to explicitly declare the type. -These declarations are not recommended because programmers would need to find its return value and understand the variable type by looking at the method. +However, the compiler can inherit type parameters from the right value (???). Therefore, it will not force users to declare the type explicitly. +These declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md index 0567ee08ae..1c43587e38 100644 --- a/info/guide/guide-chapter-5.md +++ b/info/guide/guide-chapter-5.md @@ -6,48 +6,47 @@ You should utilize this approach, along with functional style, when you write Ko The concepts behind functional style are as follows: Functions are the smallest unit of combinable and reusable code. They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code. -The code in functions should be simple, and should not conceal the author's original intentions. +The code in functions should be simple and not conceal the author's original intentions. Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner. -The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes. +The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes (???). The only exceptions to this are state machines. -Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming. -This language features built-in mechanisms that support functional programming. In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. +Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. +In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input. -The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls and each step features the following characteristics: -1. Simple -2. Verifiable -3. Testable -4. Replaceable -5. Pluggable -6. Extensible +The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, and each step features the following characteristics: +1. Simplicity +2. Verifiability +3. Testability +4. Replaceability +5. Pluggability +6. Extensibility 7. Immutable results -There can be only one side effect in this data stream, which can be placed only at the end of execution queue. +There can be only one side effect in this data stream, which can be placed only at the end of the execution queue. -### Rule 5.1.1: Avoid functions that are too long. They should consist of 30 lines (non-empty and non-comment) in total. +### Rule 5.1.1: Avoid functions that are too long. The function should be displayable on one screen and only implement one certain logic. -If a function is too long, it often means that it is complex and be split or made more primitive. +If a function is too long, it often means that it is complex and be split or made more primitive. Functions should consist of 30 lines (non-empty and non-comment) in total. **Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness. Linter warnings for such functions **can be suppressed**. -Even if a long function works well, new problems or bugs due to complex logic may appear once it is modified by someone else. -As such, it is recommended that you split such functions into several separated and shorter ones that are easier to manage. -This will enable other programmers to read and modify the code properly. - -### Rule 5.1.2: Avoid deep nesting of function code blocks. It should be limited to four levels. +Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else. +Therefore, it is recommended that you split such functions into several separate and shorter functions that are easier to manage. +This approach will enable other programmers to read and modify the code properly. +### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels. The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when). Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops). -**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function, and the nesting levels of enclosing methods are not accumulated. -Functional decomposition should be implemented to avoid confusing for the developer who read the code. +**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function wheres the nesting levels of enclosing methods are not accumulated. +Functional decomposition should be implemented to avoid confusion for the developer who reads the code. This will help the reader switch between context. ### Rule 5.1.3: Avoid using nested functions. -Nested functions create more complex function context, thereby confusing readers. -Additionally, the visibility context may not be obvious to the reader of the code. +Nested functions create a more complex function context, thereby confusing readers. +Also, the visibility context (???) may not be evident to the code reader. **Invalid example**: ```kotlin @@ -61,9 +60,9 @@ fun foo() { ### 5.2 Function arguments -### Rule 5.2.1: The lambda parameter of the function should be placed last in the argument list. +### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list. -With a such notation, it is easier to use curly brackets, which in turn leads to code with better readability. +With such notation, it is easier to use curly brackets, which in turn leads to better code readability. **Valid example**: ```kotlin @@ -78,17 +77,16 @@ println("hey") } ``` -### Rule 5.2.2: Number of parameters of function should be limited to 5 +### Rule 5.2.2: Number of function parameters should be limited to 5 A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code. -If there are **more than five** parameters, maintenance becomes more difficult and conflicts become much more difficult to merge. -As such, it is recommended that you reduce the number of parameters. -If groups of parameters appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class. +It is recommended that you reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. +If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class. It is recommended that you use Data Classes and Maps to unify these function arguments. ### Rule 5.2.3 Use default values for function arguments instead of overloading them -In Java default values for function arguments are prohibited. That's why each time when it is needed to create a function with less arguments, this function should be overloaded. -In Kotlin you can use default arguments instead. +In Java, default values for function arguments are prohibited. That is why when you need to create a function with fewer arguments, the function should be overloaded. +In Kotlin, you can use default arguments instead. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index 1f3f403298..db17a5a7ad 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -27,15 +27,14 @@ class Test private constructor(var a: Int) { ``` ### Rule 6.1.2: Prefer data classes instead of classes without any functional logic. -Some people say that data class - is a code smell. But in case you really need to use it and your x1code is becoming more simple because of that - -you can use Kotlin `data classes`. Main purpose of these classes is to hold data. -But also `data classes` will automatically generate several useful methods: +Some people say that the data class is a code smell. But if you need to use it, and as a result, your x1code is becoming more simple, you can use `.Kotlin data classes` (???). The main purpose of these classes is to hold data, +but also `data classes` will automatically generate several useful methods: - equals()/hashCode() pair; - toString() - componentN() functions corresponding to the properties in their order of declaration; - copy() function -So instead of using `normal` classes: +Therefore, instead of using `normal` classes: ```kotlin class Test { @@ -64,17 +63,16 @@ class Test() { } ``` -**Prefer:** +**Prefer (???):** ```kotlin data class Test1(var a: Int = 0, var b: Int = 0) ``` -**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to data class. -**Exception #2**: No need to convert a class to data class in case this class extends some other class or implements an interface. +**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to a data class. +**Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface. -### Rule 6.1.3: Do not use the primary constructor if it is empty and has no sense. -The primary constructor is part of the class header: it goes after the class name (and optional type parameters). -But in is useless - it can be omitted. +### Rule 6.1.3: Do not use the primary constructor if it is empty and (???)has no sense. +The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless. **Invalid example**: ```kotlin @@ -111,11 +109,11 @@ class Test { ### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That's why Kotlin has introduced `init` blocks. These blocks are used to store the code that should be run during the initialization of the class. -Kotlin allows to write multiple initialization blocks that are executed in the same order as they appear in the class body. -Even when you have the (rule 3.2)[#s3.2] this makes code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code. -So in your code you should try to use single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment -of some class property - you can use powerful functional programming. This will reduce the possibility of the error, when occasionally someone will change the order of your `init` blocks. -And it will make the logic of the code more coupled. It is always enough to use one `init` block to implement your idea in Kotlin. +Kotlin allows writing multiple initialization blocks that are executed in the same order as they appear in the class body. +Even when you follow (rule 3.2)[#s3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code. +So in your code, you should try to use a single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment +of some class property, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and +make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin. **Invalid example**: ```kotlin @@ -146,9 +144,9 @@ class YourClass(var name: String) { } ``` -Also - init block was not added to Kotlin to help you simply initialize your properties it is needed for more complex tasks. -So if `init` block contains only assignments of variables - move it directly to properties, so they will be correctly initialized near the declaration. -In some case this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you. +The `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks. +Therefore if the `init` block contains only assignments of variables - move it directly to properties, so that they will be correctly initialized near the declaration. +In some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you. **Invalid example**: ```kotlin @@ -184,8 +182,8 @@ class Square() : Rectangle() { ``` ### Rule 6.1.6: Abstract class should have at least one abstract method. -Abstract classes are used to force a developer to implement some of its parts in its inheritors. -In case when abstract class has no abstract methods - then it was set `abstract` incorrectly and can be converted to a normal class. +Abstract classes are used to force a developer to implement some of its parts in their inheritors. +When the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class. **Invalid example**: ```kotlin @@ -215,7 +213,7 @@ class NotAbstract { ### Rule 6.1.7: in case of using "implicit backing property" scheme, the name of real and back property should be the same. Kotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties). -In some cases implicit backing is not enough and it should be done explicitly: +In some cases, implicit backing is not enough and it should be done explicitly: ```kotlin private var _table: Map? = null val table: Map @@ -227,12 +225,12 @@ val table: Map } ``` -In this case the name of backing property (`_table`) should be the same to the name of real property (`table`), but should have underscore (`_`) prefix. +In this case the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. It is one of the exceptions from the [identifier names rule](#r1.2) ### Recommendation 6.1.8: avoid using custom getters and setters. Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields). -Kotlin compiler automatically generates `get` and `set` methods for properties and also lets the possibility to override it: +Kotlin compiler automatically generates `get` and `set` methods for properties and also provides the possibility to override it: ```kotlin // Bad example ====== class A { @@ -246,9 +244,9 @@ class A { ``` From the callee code these methods look like an access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter. -But in all cases it is very confusing when `get` and `set` are overriden for a developer who uses this particular class. -Developer expects to get the value of the property, but receives some unknown value and some extra side effect hidden by the custom getter/setter. -Use extra functions for it instead. +However, when `get` and `set` are overridden, it is very confusing for a developer who uses this particular class. +The developer expects to get the property value but receives some unknown value and some extra side effects (or effect??? ) hidden by the custom getter/setter. +Use extra functions for it instead (??? for what?). **Valid example**: ```kotlin @@ -264,8 +262,8 @@ class A { ``` ### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug). -Even if you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter -as it can accidentally cause a recursive call and a `StackOverflow Error`. Use `field` keyword instead. +Even (???) if you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter +as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead. **Invalid example (very bad)**: ```kotlin @@ -278,9 +276,9 @@ var isEmpty: Boolean ``` ### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. -In Java - trivial getters - are getters that are simply returning the value of a field. -Trivial setters - are simply setting the field with a value without any transformation. -But in Kotlin trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data-structures in Kotlin. +In Java, trivial getters - are the getters that are just returning the field value. +Trivial setters - are merely setting the field with a value without any transformation. +However, in Kotlin, trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data structures in Kotlin. **Invalid example**: ```kotlin @@ -305,9 +303,9 @@ class A { ``` ### Rule 6.1.11: use apply for grouping object initialization. -In the good old Java before functional programming became popular - lot of classes from commonly used libraries used configuration paradigm. -To use these classes you had to create an object with the constructor that had 0-2 arguments and set the fields that were needed to run an object. -In Kotlin to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: +In Java, before functional programming became popular, many classes from common libraries used configuration paradigm. +To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. +In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: **Invalid example**: ```kotlin @@ -353,16 +351,17 @@ fun main() { ### 6.2 Extension functions -[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) - is a killer-feature in Kotlin. +[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature (???) in Kotlin. It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy. Extension functions are resolved statically. ### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. -It is recommended that for classes non-tightly coupled functions with rare usages in the class should be implemented as extension functions where possible. -They should be implemented in the same class/file where they are used. This is non-deterministic rule, so it cannot be checked or fixed automatically by static analyzer. +It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. +They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so it cannot be checked or fixed (???) automatically by a static analyzer. -### Rule 6.2.2: there should be no extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). -As extension functions are resolved statically. In this case there can be a situation when a developer implements two extension functions - one is for the base class and another one for the inheritor. +### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). +As extension functions are resolved statically (If???). In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. + This can lead to an issue when an incorrect method is used. And that can lead to an issue when incorrect method is used. **Invalid example**: @@ -383,18 +382,17 @@ fun main() { printClassName(B()) } ### 6.3 Interfaces -`Interface`s in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. +An `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties, but these need to be abstract or to provide accessor implementations. Kotlin's interfaces can define attributes and functions. -In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design, and should take precedence over the use of (abstract) classes. +In Kotlin and Java, the interface is the main presentation means of application programming interface (API) design and should take precedence over the use of (abstract) classes. ### 6.4 Objects ### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. -As described in [6.2 Extension functions](#c6.2) - extension functions - is a very powerful mechanism. -So instead of using utility classes/objects, use it instead. -This allows you to remove the unnecessary complexity and wrapping class/object and to use top-level functions instead. +As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. +This allows you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. **Invalid example**: ```kotlin @@ -416,8 +414,8 @@ fun String.stringInfo(): Int { ``` ### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. -Kotlin’s object are extremely useful when we need to implement a some interface from an external library that doesn’t have any state. -No need to use class for such structures. +Kotlin’s objects are extremely useful when you need to implement some interface from an external library that doesn’t have any state. +There is no need to use classes for such structures. **Valid example**: ``` From d48d4e99a720d1f55677a2d1a74753d34a867ddf Mon Sep 17 00:00:00 2001 From: akuleshov7 Date: Mon, 23 Nov 2020 12:24:20 +0300 Subject: [PATCH 02/18] Review notes ### What's done: Review notes --- info/guide/guide-chapter-0.md | 4 ++-- info/guide/guide-chapter-1.md | 25 ++++++++++++------------- info/guide/guide-chapter-2.md | 10 +++++----- info/guide/guide-chapter-3.md | 29 +++++++++++++++-------------- info/guide/guide-chapter-4.md | 6 +++--- info/guide/guide-chapter-5.md | 4 ++-- info/guide/guide-chapter-6.md | 22 +++++++++++----------- 7 files changed, 50 insertions(+), 50 deletions(-) diff --git a/info/guide/guide-chapter-0.md b/info/guide/guide-chapter-0.md index 0a008e8241..0b04b6b4f8 100644 --- a/info/guide/guide-chapter-0.md +++ b/info/guide/guide-chapter-0.md @@ -28,7 +28,7 @@ Also, we need to consider the following factors when programming on Kotlin: Kotlin combines two of the main programming paradigms: functional and object-oriented. Both of these paradigms are trusted and well-known software engineering practices. - As a young programming language, Kotlin builds (???) on well-established languages such as Java, C++, C#, and Scala. + As a young programming language, Kotlin is built on the top of well-established languages such as Java, C++, C#, and Scala. This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar. 2. Following Kotlin idioms @@ -60,5 +60,5 @@ Unless otherwise stated, this specification applies to versions 1.3 and later of Even though exceptions may exist, it is essential to understand why rules and recommendations are needed. Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. -When modifying open-source code or third-party code, you can choose to implement the code's style (???) used by the code (instead of using the existing specifications) to maintain consistency. +When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency. Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. \ No newline at end of file diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 2ac39cae27..75aaa2eadb 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -1,18 +1,18 @@ # 1. Naming -In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, magic numbers (???), and inappropriate abbreviations. +In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations. Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. ### 1.1 Identifier names ### 1.1.1: Identifiers naming conventions -**Rule (???):** For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. Explanation: Each valid identifier name should match the regular expression `\w{2,64}`. `{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility. -Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking, for example (???). No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. +Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking. +No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. 2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension. @@ -74,9 +74,8 @@ Package names are all written in lowercase, and consecutive words are concatenat **Exceptions:** - In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.` -- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name or the package name contains reserved Java keywords, underscores are allowed. (???) -- Underscores are sometimes permitted if the package name contains reserved Java keywords, such as org.example.hyphenated_name, int_.example, com.example._123name -Examples: `org.example.hyphenated_name`,` int_.example`, `com.example._123name` +- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`. +- Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`. **Valid example**: ```kotlin @@ -86,7 +85,7 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces ### Rule 1.3.1: Classes, enumerations, interface names use Camel case -Classes, enumerations, and interface names use camel case nomenclature (???). Follow the naming rules described below: +Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below: 1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`). Note that verbs are not used to name classes. However, nouns (such as `Customer`, `WikiPage`, and `Account`) can be used. Try to avoid using vague words such as `Manager` and `Process`. @@ -111,8 +110,8 @@ class Order {} ### 1.4 Functions -### Rule 1.4.1: Function names should be in camel case (???) -Function names should be in camel (???) case. Follow the naming rules described below: +### Rule 1.4.1: Function names should be in camel case +Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. To name functions use the following formatting rules: @@ -158,10 +157,10 @@ fun draw() fun addKeyListener(Listener) ``` -2. An underscore can be included in the JUnit test function name and should be a logical component used to separate names (???). Each logical part denoted in lowerCamelCase (???), for example, a typical pattern of using underscore: pop_emptyStack. +2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. ### 1.5 Constants -### Rule 1.5.1 Constant names should be in UPPER case, words separated by underscore (???) +### Rule 1.5.1 Constant names should be in UPPER case, words in the name are separated by underscore Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. @@ -170,7 +169,7 @@ Constant names should be in UPPER case, words separated by underscore. The jener 2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. 3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. -4. Use meaningful constants instead of `magic numbers` (???). SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. +4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. You can avoid using magic numbers with the following method: @@ -198,7 +197,7 @@ Non-constant field names should use camel case and start with a lowercase letter A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. For example: `var namesList: List` -Names of non-constant variables should use lower camel case (???). The name of the final immutable field used to store the singleton object can use the same camel case notation. +Names of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 212923051d..6f5592d67b 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -38,7 +38,7 @@ All properties of the primary constructor should be also documented in a KDoc wi **Exceptions:** -1. For setters/getters of properties, obvious comments are optional (???). Note that Kotlin generates simple `get/set` methods under the hood). For example, getFoo can also be `return foo`. +1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood. 2. It is optional to add comments for simple one-line methods, such as shown in the example below: ```kotlin @@ -107,7 +107,7 @@ Kdoc should not contain: - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. -If a tag block cannot be described in one line, you should indent the content of the new line by `4 spaces` (???) from the `@` position to achieve alignment (`@` counts as one + three spaces). +If a tag block cannot be described in one line, you should indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). **Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. See [3.8 Horizontal space](#c3.8). @@ -144,7 +144,7 @@ The following examples for Huawei describe the format of the **copyright license Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \ English version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.` -Regarding the **release notes**, see examples below (???): +Regarding the **release notes**, see examples below: - `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. These two years can be the same (for example, `2020–2020`). When the file is substantially changed (for example, through feature extensions and major refactorings), the subsequent years must be updated. @@ -164,7 +164,7 @@ The following example is a copyright statement for Huawei, without other functio The following factors should be considered when writing the file header or comments for top-level classes: - File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline. -- Maintain a unified format. The specific format can be formulated (???) by the project (for example, in opensource), and you need to follow it. +- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. - Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted. - The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. @@ -183,7 +183,7 @@ The function header comment's content is optional, but not limited to function d ### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: - There must be one space between the comment character and the content of the comment -- There must be a newline (???) between a Kdoc and the pressiding code +- There must be a newline between a Kdoc and the pressiding code - An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 0db8e9f462..0425a8780e 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -4,8 +4,8 @@ ### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines). If the file is too long and complex, it should be split into smaller files, functions, or modules. -It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy, respectively (???). The only exception to this rule is code generation. (???) -The auto-generated files that are not manually modified can be longer +It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. +The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. ### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. @@ -80,7 +80,7 @@ All variants of a `(private) val` logger should be placed in the beginning of th ### 3.2 Braces ### Rule 3.2.1: Braces must be used in conditional statements and loop blocks. -Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for statements with one line (???). +Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements. **Valid example:** @@ -179,7 +179,7 @@ do { ### 3.3 Indentation ### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces. -Only spaces are permitted for indentation, and each indentation should equal `4 spaces` (tabs are not permitted) (???). +Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted). If you prefer using tabs, simply configure them to automatically change to spaces in your IDE. These code blocks should be indented if they are placed on the new line, and the following conditions are met: - The code block is placed immediately after an opening brace @@ -220,7 +220,7 @@ if (condition) ``` **Exceptions**: -- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces` (???). A parameter that was moved to a new line can be on the same level as the previous argument: +- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument: ```kotlin fun visit( @@ -295,7 +295,7 @@ The international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: - One wide character occupies the width of two narrow characters. -The "wide" and "narrow" parts of a character are defined by (???) its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/). +The "wide" and "narrow" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/). Typically, narrow characters are also called "half-width" characters. All characters in the ASCII character set include letters (such as `a, A`), numbers (such as `0, 3`), and punctuation spaces (such as `,` , `{`), all of which are narrow characters. Wide characters are also called "full-width" characters. Chinese characters (such as `中, 文`), Chinese punctuation (`,` , `;` ), full-width letters and numbers (such as `A、3`) are "full-width" characters. @@ -330,7 +330,7 @@ val b = "" 1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline. There should be no redundant semicolon at the end of the lines. -When a newline (???) is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). +When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`. Note that all comparison operators, such as `==`, `>`, `<`, should not be split. @@ -393,7 +393,7 @@ value.map { name -> val someValue = { node:String -> node } ``` -6) When the function contains only a single expression, it can be expressed (???) as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions). +6) When the function contains only a single expression, it can be written as [expression function](https://kotlinlang.org/docs/reference/functions.html#single-expression-functions). The below example shows the style that should not be used. Instead of: @@ -476,10 +476,10 @@ fun baz() { **Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.) -1. Separate all (???) keywords (such as `if`, `when`, and `for`) from the opening parenthesis with single whitespace. - The only exception is the `constructor` keyword, which should not be separated. +1. Separate keywords like `if`, `when`, `for`, e.t.c. from the opening parenthesis with single whitespace. + The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis. -2. Separate all keywords (???) (such as `else` or `try`) from the opening brace (`{`) with a single whitespace. +2. Separate keywords like `else` or `try` from the opening brace (`{`) with a single whitespace. If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()` 3. Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses: @@ -588,7 +588,7 @@ enum class Warnings { } ``` -This will help resolve conflicts and reduce the value's number (???) during merging pull requests. +This will help to resolve conflicts and reduce the number of conflicts during merging pull requests. Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma). 2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line: @@ -596,14 +596,15 @@ Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html# enum class Suit { CLUBS, HEARTS, SPADES, DIAMONDS } ``` -3) Enum classes take preference if possible (???), for example, instead of two Boolean properties, such as shown below: +3) Enum classes take preference (if it is possible to use it). For example, instead of two boolean properties: ```kotlin val isCelsius = true val isFahrenheit = false ``` -Using enum class: +use enum class: + ```kotlin enum class TemperatureScale { CELSIUS, FAHRENHEIT } ``` diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index 47f96c582b..680fde253a 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -29,7 +29,7 @@ Float values containing more than six or seven decimal numbers will be rounded. println(income.subtract(expense)) // you will obtain 0.9 here ``` -### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like compareTo and equals (???). +### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like `compareTo()` and `equals()`. Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems. **Invalid example**: @@ -151,7 +151,7 @@ typealias Predicate = (T) -> Boolean Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. ### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. -To avoid `NullPointerException` and help compiler checks prevent NPE (???) avoid using nullable types (with `?` symbol). +To avoid `NullPointerException` and help compiler to prevent Null Poniter Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: ```kotlin @@ -184,7 +184,7 @@ Like in Java, classes in Kotlin may have type parameters. To create an instance val myVariable: Map = emptyMap() ``` -However, the compiler can inherit type parameters from the right value (???). Therefore, it will not force users to declare the type explicitly. +However, the compiler can inherit type parameters from the r-value (value assigned to a variable). Therefore, it will not force users to declare the type explicitly. These declarations are not recommended because programmers would need to find the return value and understand the variable type by looking at the method. **Invalid example**: diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md index 5a7c2bbdd6..5f0f5b7403 100644 --- a/info/guide/guide-chapter-5.md +++ b/info/guide/guide-chapter-5.md @@ -8,7 +8,7 @@ Functions are the smallest unit of combinable and reusable code. They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code. The code in functions should be simple and not conceal the author's original intentions. Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner. -The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes (???). +The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes of an object. The only exceptions to this are state machines. Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. @@ -46,7 +46,7 @@ This will help the reader switch between context. ### Rule 5.1.3: Avoid using nested functions. Nested functions create a more complex function context, thereby confusing readers. -Also, the visibility context (???) may not be evident to the code reader. +With nested functions the visibility context may not be evident to the code reader. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index a5bfbd424f..6ad5cac182 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -27,8 +27,8 @@ class Test private constructor(var a: Int) { ``` ### Rule 6.1.2: Prefer data classes instead of classes without any functional logic. -Some people say that the data class is a code smell. But if you need to use it, and as a result, your x1code is becoming more simple, you can use `.Kotlin data classes` (???). The main purpose of these classes is to hold data, -but also `data classes` will automatically generate several useful methods: +Some people say that the data class is a code smell. But if you need to use it, and as a result, your code is becoming more simple, you can use Kotlin `data class`. The main purpose of this class is to hold data, +but also `data class` will automatically generate several useful methods: - equals()/hashCode() pair; - toString() - componentN() functions corresponding to the properties in their order of declaration; @@ -63,7 +63,7 @@ class Test() { } ``` -**Prefer (???):** +**prefer data classes:** ```kotlin data class Test1(var a: Int = 0, var b: Int = 0) ``` @@ -72,7 +72,7 @@ data class Test1(var a: Int = 0, var b: Int = 0) **Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface. -### Rule 6.1.3: Do not use the primary constructor if it is empty and (???)has no sense. +### Rule 6.1.3: Do not use the primary constructor if it is empty or useless. The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless. **Invalid example**: @@ -249,8 +249,8 @@ class A { From the callee code these methods look like an access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter. However, when `get` and `set` are overridden, it is very confusing for a developer who uses this particular class. -The developer expects to get the property value but receives some unknown value and some extra side effects (or effect??? ) hidden by the custom getter/setter. -Use extra functions for it instead (??? for what?). +The developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter. +Use extra functions instead to avoid confusion. @@ -270,7 +270,7 @@ class A { **Exception:** `Private setters` are only exceptions that are not prohibited by this rule. ### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug). -Even (???) if you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter +If you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead. **Invalid example (very bad)**: @@ -359,17 +359,17 @@ fun main() { ### 6.2 Extension functions -[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature (???) in Kotlin. +[Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin. It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy. Extension functions are resolved statically. ### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. -They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so it cannot be checked or fixed (???) automatically by a static analyzer. +They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer. ### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). -As extension functions are resolved statically (If???). In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. - This can lead to an issue when an incorrect method is used. +As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. +This can lead to an issue when an incorrect method is used. And that can lead to an issue when incorrect method is used. **Invalid example**: From 9d65a6b5cd858152fa2ea94b2f05ba1f45d7790d Mon Sep 17 00:00:00 2001 From: vtchem Date: Mon, 30 Nov 2020 13:53:30 +0300 Subject: [PATCH 03/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-chapter-0.md | 8 +++---- info/guide/guide-chapter-1.md | 24 +++++++++---------- info/guide/guide-chapter-2.md | 42 ++++++++++++++++++---------------- info/guide/guide-chapter-3.md | 42 +++++++++++++++++----------------- info/guide/guide-chapter-4.md | 15 ++++++------ info/guide/guide-chapter-5.md | 28 +++++++++++------------ info/guide/guide-chapter-6.md | 43 +++++++++++++++++------------------ info/guide/guide-chapter-8.md | 6 +++-- 8 files changed, 105 insertions(+), 103 deletions(-) diff --git a/info/guide/guide-chapter-0.md b/info/guide/guide-chapter-0.md index 0b04b6b4f8..7d010dbacf 100644 --- a/info/guide/guide-chapter-0.md +++ b/info/guide/guide-chapter-0.md @@ -20,7 +20,7 @@ For the code to be considered high-quality, it must entail the following charact Like other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles: 1. Clarity — a necessary feature of programs that are easy to maintain and refactor. 2. Simplicity — a code is easy to understand and implement. -3. Consistency — enables a code to be easily modified, reviewed and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles.enables code to be easily modified, reviewed and understood by the team members. +3. Consistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members. Also, we need to consider the following factors when programming on Kotlin: @@ -28,8 +28,8 @@ Also, we need to consider the following factors when programming on Kotlin: Kotlin combines two of the main programming paradigms: functional and object-oriented. Both of these paradigms are trusted and well-known software engineering practices. - As a young programming language, Kotlin is built on the top of well-established languages such as Java, C++, C#, and Scala. - This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar. + As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C#, and Scala. + This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, "when" statements, much easier work with collections, type auto conversion, and other syntactic sugar. 2. Following Kotlin idioms @@ -59,6 +59,6 @@ Unless otherwise stated, this specification applies to versions 1.3 and later of ### Exceptions Even though exceptions may exist, it is essential to understand why rules and recommendations are needed. -Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. +Depending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency. Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. \ No newline at end of file diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 75aaa2eadb..7b3db3d42d 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -1,5 +1,5 @@ # 1. Naming -In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations. +In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps to clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations. Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. @@ -12,7 +12,7 @@ For identifiers, use the following naming conventions: Explanation: Each valid identifier name should match the regular expression `\w{2,64}`. `{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility. Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking. -No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. +No special prefix or suffix should be used in names. The following examples are inappropriate names: name_, mName, s_name, and kName. 2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension. @@ -50,7 +50,7 @@ The only exception is function names in `Unit tests.` | n,h | h,n | nr, head, height | | rn, m | m,rn | mbr, item | -**Exceptions** +**Exceptions:** - The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables. - The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}` - The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively. @@ -69,12 +69,12 @@ Note that prefixing can also negatively affect the style and the auto-generation ### Rule 1.2.1: Package names dots Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. Each file should have a `package` directive. -Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product and module names, and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. +Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. **Exceptions:** - In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.` -- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`. +- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`. - Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`. **Valid example**: @@ -114,7 +114,7 @@ class Order {} Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. -To name functions use the following formatting rules: +To name functions, use the following formatting rules: a) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }. ```kotlin @@ -164,17 +164,17 @@ fun addKeyListener(Listener) Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. -1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. +1. Constants are attributes created with the const keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. -2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. -3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. +2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. +3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. 4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. You can avoid using magic numbers with the following method: - Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`. -- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9) +- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9). **Invalid example**: @@ -194,7 +194,7 @@ const val String APPLICATION_NAME = "Launcher"; ### 1.6 Non-constant fields (variables) ### Rule 1.6.1: Non-constant field name Non-constant field names should use camel case and start with a lowercase letter. -A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. +A local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. For example: `var namesList: List` Names of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation. @@ -214,7 +214,7 @@ val mutableCollection: MutableSet = HashSet() ### Rule 1.6.2: Boolean variable names with negative meaning -Avoid using Boolean variable names with negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". +Avoid using Boolean variable names with a negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". For instance, it is not easy to understand the meaning of !isNotError. The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes. However, not all methods returning Boolean type have this notation. diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 9949be1ea7..9a9b7b4d61 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -35,9 +35,9 @@ Use a single-line form when you store the entire KDoc block in one line (and the At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). Other code blocks can also have KDocs if needed. Instead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class. -All properties of the primary constructor should be also documented in a KDoc with a `@property` tag. +All properties of the primary constructor should also be documented in a KDoc with a `@property` tag. -Incorrect example: +**Incorrect example:** ```kotlin /** * Class description @@ -52,7 +52,7 @@ class Example( ) ``` -Correct example: +**Correct example:** ```kotlin /** * Class description @@ -67,7 +67,7 @@ class Example( **Exceptions:** -1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood. +1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood. 2. It is optional to add comments for simple one-line methods, such as shown in the example below: ```kotlin @@ -130,18 +130,20 @@ Therefore, Kdoc should contain the following: - `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc. - `@implNote`: A note related to API implementation, which implementers should keep in mind. - One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments. -- The conventional standard "block labels" arranged in the following order: `@param`, `@return`, `@throws`. +- The conventional standard "block labels" are arranged in the following order: `@param`, `@return`, `@throws`. Kdoc should not contain: - Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space. - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. -If a tag block cannot be described in one line, you should indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). +If a tag block cannot be described in one line, indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). -**Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. +**Exception:** + +When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. See [3.8 Horizontal space](#c3.8). -In Kotlin, compared to Java, you are able to put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). +In Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag. **Examples:** @@ -167,7 +169,7 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo ### 2.2 Comments to the file header ### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. -Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format. +Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format. The following examples for Huawei describe the format of the **copyright license**: \ Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \ @@ -178,7 +180,7 @@ Regarding the **release notes**, see examples below: - `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. These two years can be the same (for example, `2020–2020`). When the file is substantially changed (for example, through feature extensions and major refactorings), the subsequent years must be updated. -- The **copyright statement** can use your company's subsidiaries. For example: \ +- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \ Chinese version: `版权所有 (c) 海思半导体 2012-2020` \ English version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.` @@ -193,9 +195,9 @@ The following example is a copyright statement for Huawei, without other functio The following factors should be considered when writing the file header or comments for top-level classes: - File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline. -- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it. +- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. -- Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted. +- Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted. - The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. @@ -212,8 +214,8 @@ The function header comment's content is optional, but not limited to function d ### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: - There must be one space between the comment character and the content of the comment -- There must be a newline between a Kdoc and the pressiding code -- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). +- There must be a newline between a Kdoc andpressiding code +- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** ```kotlin @@ -255,7 +257,7 @@ It is a good practice to add a blank line between the body of the comment and Kd ``` - Leave one single space between the comment on the right side of the code and the code. -If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes your code more understandable. +If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable. When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces. Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`. @@ -283,7 +285,7 @@ val someVal = if (nr % 15 == 0) { } ``` -- Start all comments (including KDoc) with a space after the first symbol (`//`, `/*`, `/**` and `*`) +- Start all comments (including KDoc) with space after the first symbol (`//`, `/*`, `/**` and `*`) **Valid example:** ```kotlin @@ -293,9 +295,9 @@ val x = 0 // this is a comment ### Rule 2.4.2: Do not comment on unused code blocks Do not comment on unused code blocks, including imports. Delete these code blocks immediately. A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose. -Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be properly maintained. -When you attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed. -The correct approach is to delete the unnecessary code directly and immediately when it is not used. +Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained. +In an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed. +The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. ### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. @@ -303,7 +305,7 @@ The code officially delivered to the client typically should not contain TODO/FI `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. They should all have a unified style to facilitate the unified text search processing. -**For example**: +**Example**: ```kotlin // TODO(): Jira-XXX - support new json format // FIXME: Jira-XXX - fix NPE in this code block diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 0425a8780e..10e6dcd026 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -9,6 +9,7 @@ The only exception to this rule is code generation - the auto-generated files th ### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. + a) Code blocks should be in the following order: 1. Kdoc for licensed or copyrighted files 2. `@file` annotation @@ -21,7 +22,7 @@ b) Each of the preceding code blocks should be separated by a blank line. c) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - `*`). -d) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename +d) **Recommendation**. One `.kt` source file should contain only one class declaration, and its name should match the filename e) Avoid empty files that do not contain the code or contain only imports/comments/package name @@ -58,8 +59,7 @@ import kotlinx.coroutines.* // official kotlin extension library ### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. Notes: -1. There should be no blank lines between properties. -**Exceptions**: When there is a comment before a property on a separate line or annotations on a separate line. +1. There should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line. 2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc. 3. Enum entries and constant properties (`const val`) in companion objects should be alphabetically arranged. @@ -123,12 +123,12 @@ if (condition) { Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces: - The opening brace and first line of the code block are on the same line. - The closing brace is on its own new line. -- The closing brace can be followed by a newline. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords. -These keywords should not be split from the closing brace by a newline. +- The closing brace can be followed by a newline character. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords. +These keywords should not be split from the closing brace by a newline character. **Exception cases**: -1) For lambdas, there is no need to put a newline after the first (function-related) opening brace. A newline should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)). +1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)). ```kotlin arg.map { value -> @@ -180,7 +180,7 @@ do { ### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces. Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted). -If you prefer using tabs, simply configure them to automatically change to spaces in your IDE. +If you prefer using tabs, simply configure them to change to spaces in your IDE automatically. These code blocks should be indented if they are placed on the new line, and the following conditions are met: - The code block is placed immediately after an opening brace - The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.) @@ -220,7 +220,7 @@ if (condition) ``` **Exceptions**: -- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument: +- When breaking the parameter list of a method/class constructor, it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument: ```kotlin fun visit( @@ -239,7 +239,7 @@ val abcdef = "my splitted" + " string" ``` -- A list of supertypes should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if the leading colon is also on a separate line +- A list of supertypes should be indented with `4 spaces` if they are on different lines or with `8 spaces` if the leading colon is also on a separate line ```kotlin class A : @@ -263,7 +263,7 @@ override fun foo() { } ``` -**Valid examples** (but note once again, that generally empty blocks are prohibited): +**Valid examples** (note once again that generally empty blocks are prohibited): ```kotlin fun doNothing() {} @@ -327,11 +327,11 @@ val b = "" ### Rule 3.6.2: Rules for line-breaking -1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline. +1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character. There should be no redundant semicolon at the end of the lines. -When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). -However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`. +When a newline character is needed to split the line, it should be placed after such operators as `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). +However, the newline character should be placed before operators such as `.`, `?.`, `?:`, and `::`. Note that all comparison operators, such as `==`, `>`, `<`, should not be split. @@ -372,7 +372,7 @@ if (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1) A brace should be placed immediately after the name without any spaces in declarations or at call sites. 4) Newlines should be placed right after the comma (`,`). 5) If a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters. - If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`). + If it uses an implicit parameter (`it`), the newline character should be placed after the opening brace (`{`). The following examples illustrate this rule: @@ -512,7 +512,7 @@ fun baz() { There should be no spaces before `,` , `:` and `;`. **Exceptions** for spaces and colons are the following: - - when `:` is used to separate a type and a super type, including an anonymous object (after object keyword) + - when `:` is used to separate a type and a supertype, including an anonymous object (after object keyword) - when delegating to a superclass constructor or different constructor of the same class **Valid example:** @@ -526,7 +526,7 @@ fun baz() { } ``` -6. There should be *only one space* between the identifier and it's type: `list: List` +6. There should be *only one space* between the identifier and its type: `list: List` If the type is nullable, there should be no space before `?`. 7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`. @@ -543,7 +543,7 @@ fun foo 9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates). -10. There should be no spaces between prefix/postfix operator (like `!!` or `++`), and it's an operand. +10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand. ### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. @@ -551,7 +551,7 @@ fun foo - When modifying code, it takes much time for new developers to format, support, and fix alignment issues. - Long identifier names will break the alignment and lead to less presentable code. -- Alignment possesses more disadvantages than advantages. To reduce maintenance costs, misalignment is the best choice. +- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice. Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability: ```kotlin @@ -649,7 +649,7 @@ The compiler can issue a warning when it is missing. ### 3.12 Annotations ### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. -1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line). +1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). **Valid example**: ```kotlin @@ -734,7 +734,7 @@ val bytes = 0b11010010_01101001_10010100_10010010 ### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: [String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) -As such, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines and you do not need to split them with newlines. +Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline charcters. **Invalid example**: ```kotlin @@ -764,7 +764,7 @@ val someString = "$myArgument ${myArgument.foo()}" **Redundant string template** -In case string template contains only one variable - there is no need to use string template. Use this variable directly. +In case a string template contains only one variable - there is no need to use the string template. Use this variable directly. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index 680fde253a..5485ceab75 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -16,13 +16,13 @@ However, it will print the following value: `0.8999999999999999` Therefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended. The `BigDecimal` type should serve as a good choice. -**Invalid example:** \ +**Invalid example**: \ Float values containing more than six or seven decimal numbers will be rounded. ```kotlin val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817 ``` -**Valid example** (when precise calculations are needed): +**Valid example**: (when precise calculations are needed): ```kotlin val income = BigDecimal("2.0") val expense = BigDecimal("1.1") @@ -90,10 +90,9 @@ The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/ref } ``` -Also Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast. -Contracts are used and are very stable in `stdlib`. +Also, Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast. +Contracts are used and are very stable in `stdlib`, for example: -For example: ```kotlin fun bar(x: String?) { @@ -151,7 +150,7 @@ typealias Predicate = (T) -> Boolean Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. ### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. -To avoid `NullPointerException` and help compiler to prevent Null Poniter Exceptions, avoid using nullable types (with `?` symbol). +To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: ```kotlin @@ -163,9 +162,9 @@ val a: Int? = 0 val a: Int = 0 ``` -Nevertheless, if you use Java libraries extensively, you will have to use nullable types and enrich your code with `!!` and `?` symbols. +Nevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with `!!` and `?` symbols. Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)). -Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null` use `emptyList()`. +Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null`, use `emptyList()`. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md index 5f0f5b7403..6ed8f268a4 100644 --- a/info/guide/guide-chapter-5.md +++ b/info/guide/guide-chapter-5.md @@ -1,20 +1,20 @@ # 5. Functions ### 5.1 Function design -You can write clean code by gaining knowledge of how to build design patterns and avoid code smells. -You should utilize this approach, along with functional style, when you write Kotlin code. +Developers can write clean code by gaining knowledge of how to build design patterns and avoid code smells. +You should utilize this approach, along with functional style, when writing Kotlin code. The concepts behind functional style are as follows: Functions are the smallest unit of combinable and reusable code. They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code. The code in functions should be simple and not conceal the author's original intentions. -Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner. -The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes of an object. +Additionally, it should have a clean abstraction, and control statements should be used straightforwardly. +The side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object. The only exceptions to this are state machines. Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. -In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. +Also, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments (???). As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input. -The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, and each step features the following characteristics: +The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics: 1. Simplicity 2. Verifiability 3. Testability @@ -28,25 +28,25 @@ There can be only one side effect in this data stream, which can be placed only ### Rule 5.1.1: Avoid functions that are too long. The function should be displayable on one screen and only implement one certain logic. -If a function is too long, it often means that it is complex and be split or made more primitive. Functions should consist of 30 lines (non-empty and non-comment) in total. +If a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total. **Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness. Linter warnings for such functions **can be suppressed**. Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else. -Therefore, it is recommended that you split such functions into several separate and shorter functions that are easier to manage. +Therefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage. This approach will enable other programmers to read and modify the code properly. ### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels. The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when). Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops). -**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function wheres the nesting levels of enclosing methods are not accumulated. +**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated. Functional decomposition should be implemented to avoid confusion for the developer who reads the code. -This will help the reader switch between context. +This will help the reader switch between contexts. ### Rule 5.1.3: Avoid using nested functions. Nested functions create a more complex function context, thereby confusing readers. -With nested functions the visibility context may not be evident to the code reader. +With nested functions, the visibility context may not be evident to the code reader. **Invalid example**: ```kotlin @@ -62,7 +62,7 @@ fun foo() { ### 5.2 Function arguments ### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list. -With such notation, it is easier to use curly brackets, which in turn leads to better code readability. +With such notation, it is easier to use curly brackets, leading to better code readability. **Valid example**: ```kotlin @@ -80,12 +80,12 @@ println("hey") ### Rule 5.2.2: Number of function parameters should be limited to 5 A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code. -It is recommended that you reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. +It is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class. It is recommended that you use Data Classes and Maps to unify these function arguments. ### Rule 5.2.3 Use default values for function arguments instead of overloading them -In Java, default values for function arguments are prohibited. That is why when you need to create a function with fewer arguments, the function should be overloaded. +In Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments. In Kotlin, you can use default arguments instead. **Invalid example**: diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index 6ad5cac182..4760a7e0f5 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -2,7 +2,7 @@ ### 6.1 Classes ### Rule 6.1.1: When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. -In case class contains only one explicit constructor - it should be converted to a primary constructor. +In case the class contains only one explicit constructor - it should be converted to a primary constructor. **Invalid example**: ```kotlin @@ -20,14 +20,14 @@ class Test(var a: Int) { // ... } -// in case of any annotations or modifiers used on constructor: +// in case of any annotations or modifiers used on a constructor: class Test private constructor(var a: Int) { // ... } ``` ### Rule 6.1.2: Prefer data classes instead of classes without any functional logic. -Some people say that the data class is a code smell. But if you need to use it, and as a result, your code is becoming more simple, you can use Kotlin `data class`. The main purpose of this class is to hold data, +Some people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data, but also `data class` will automatically generate several useful methods: - equals()/hashCode() pair; - toString() @@ -68,12 +68,12 @@ class Test() { data class Test1(var a: Int = 0, var b: Int = 0) ``` -**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to a data class. +**Exception 1**: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class. -**Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface. +**Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface. ### Rule 6.1.3: Do not use the primary constructor if it is empty or useless. -The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless. +The primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used. **Invalid example**: ```kotlin @@ -83,7 +83,7 @@ class Test() { var b: Int = 0 } -// empty primary constructor is not needed here also +// empty primary constructor is not needed here // it can be replaced with a primary contructor with one argument or removed class Test() { var a = "Property" @@ -100,7 +100,7 @@ class Test() { **Valid example**: ```kotlin -// the good example here is a data class, but this example shows that you should get rid of braces for primary constructor +// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor class Test { var a: Int = 0 var b: Int = 0 @@ -108,12 +108,11 @@ class Test { ``` ### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class. -The primary constructor cannot contain any code. That's why Kotlin has introduced `init` blocks. -These blocks are used to store the code that should be run during the initialization of the class. -Kotlin allows writing multiple initialization blocks that are executed in the same order as they appear in the class body. +The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks. +These blocks store the code to be run during the class initialization. +Kotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body. Even when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code. -So in your code, you should try to use a single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment -of some class property, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and +Therefore, you should try to use a single `init` block to reduce the code's complexity. . If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin. **Invalid example**: @@ -146,7 +145,7 @@ class YourClass(var name: String) { ``` The `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks. -Therefore if the `init` block contains only assignments of variables - move it directly to properties, so that they will be correctly initialized near the declaration. +Therefore if the `init` block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration. In some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you. **Invalid example**: @@ -167,7 +166,7 @@ class A(baseUrl: String) { ``` ### Rule 6.1.5: Explicit supertype qualification should not be used if there is not clash between called methods. -This rule is applicable for both interfaces and classes. +This rule is applicable to both interfaces and classes. **Invalid example**: ```kotlin @@ -226,12 +225,12 @@ val table: Map } ``` -In this case the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. +In this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. It is one of the exceptions from the [identifier names rule](#r1.2) ### Recommendation 6.1.8: avoid using custom getters and setters. Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields). -Kotlin compiler automatically generates `get` and `set` methods for properties and also provides the possibility to override it. +Kotlin compiler automatically generates `get` and `set` methods for properties and can override them. **Invalid example:** ```kotlin @@ -270,7 +269,7 @@ class A { **Exception:** `Private setters` are only exceptions that are not prohibited by this rule. ### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug). -If you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter +If you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead. **Invalid example (very bad)**: @@ -286,7 +285,7 @@ var isEmpty: Boolean ### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. In Java, trivial getters - are the getters that are just returning the field value. Trivial setters - are merely setting the field with a value without any transformation. -However, in Kotlin, trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data structures in Kotlin. +However, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin. **Invalid example**: ```kotlin @@ -311,7 +310,7 @@ class A { ``` ### Rule 6.1.11: use apply for grouping object initialization. -In Java, before functional programming became popular, many classes from common libraries used configuration paradigm. +In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -400,7 +399,7 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects ### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. -This allows you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. +This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. **Invalid example**: ```kotlin @@ -422,7 +421,7 @@ fun String.stringInfo(): Int { ``` ### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. -Kotlin’s objects are extremely useful when you need to implement some interface from an external library that doesn’t have any state. +Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. **Valid example**: diff --git a/info/guide/guide-chapter-8.md b/info/guide/guide-chapter-8.md index 7c19482263..225c7b61ec 100644 --- a/info/guide/guide-chapter-8.md +++ b/info/guide/guide-chapter-8.md @@ -5,7 +5,7 @@ Try to avoid explicit null checks (explicit comparison with `null`) Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. -But Kotlin architects wanted Kotlin to be fully compatible with Java, that's why `null` keyword was also introduced in Kotlin. +However, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin. There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c @@ -66,7 +66,9 @@ myVar?.let { } ?: run { println("not null") } ``` -**Exceptions:** in case of complex expressions like multiple `else-if` structures, or a long conditional statement there is a common sense to use explicit comparison with `null`. +**Exceptions:** + +In the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`. **Valid examples:** From f8e807970f66f4f123dd5375f42f557cb241c31d Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 7 Dec 2020 01:02:35 +0300 Subject: [PATCH 04/18] Update info/guide/guide-chapter-3.md Co-authored-by: Peter Trifanov --- info/guide/guide-chapter-3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 10e6dcd026..d660e04b09 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -551,7 +551,7 @@ fun foo - When modifying code, it takes much time for new developers to format, support, and fix alignment issues. - Long identifier names will break the alignment and lead to less presentable code. -- There are more disadvantages than advantages in alignment. To reduce maintenance costs, misalignment (???) is the best choice. +- There are more disadvantages than advantages in alignment. To reduce maintenance costs, the best choice is not to use horizontal alignment. Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability: ```kotlin From fa830ea3c41c813c448a734a70d2565d60e0bccf Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 7 Dec 2020 01:02:46 +0300 Subject: [PATCH 05/18] Update info/guide/guide-chapter-1.md Co-authored-by: Peter Trifanov --- info/guide/guide-chapter-1.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 7b3db3d42d..62c53a80e6 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -166,7 +166,7 @@ Constant names should be in UPPER case, words separated by underscore. The jener 1. Constants are attributes created with the const keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. -2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. +2. Constant names should contain only uppercase letters separated by underscores. They should have a `val` or `const val` modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the `const val` modifier. Note that not all `val` variables are constants. 3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. 4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. From b8e54b47b8a9372817b59ddc654d07db02480b33 Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 7 Dec 2020 01:03:21 +0300 Subject: [PATCH 06/18] Update info/guide/guide-chapter-3.md Co-authored-by: Peter Trifanov --- info/guide/guide-chapter-3.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index d660e04b09..a087e57516 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -734,7 +734,7 @@ val bytes = 0b11010010_01101001_10010100_10010010 ### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: [String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) -Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline charcters. +Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters. **Invalid example**: ```kotlin From 0c3c13b929724b172977eb2cc587d61fbcb9c270 Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 7 Dec 2020 01:03:29 +0300 Subject: [PATCH 07/18] Update info/guide/guide-chapter-2.md Co-authored-by: Peter Trifanov --- info/guide/guide-chapter-2.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 9a9b7b4d61..9145d698cd 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -136,7 +136,7 @@ Kdoc should not contain: - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. -If a tag block cannot be described in one line, indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). +If a tag block cannot be described in one line, indent the content of the new line by *four spaces* from the `@` position to achieve alignment (`@` counts as one + three spaces). **Exception:** @@ -311,4 +311,4 @@ They should all have a unified style to facilitate the unified text search proce // FIXME: Jira-XXX - fix NPE in this code block ``` -At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released. \ No newline at end of file +At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released. From 408a128cbfe7befe9d2a6c41beba9370e049745a Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 7 Dec 2020 01:03:39 +0300 Subject: [PATCH 08/18] Update info/guide/guide-chapter-2.md Co-authored-by: Peter Trifanov --- info/guide/guide-chapter-2.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 9145d698cd..3b2565fbb1 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -214,7 +214,7 @@ The function header comment's content is optional, but not limited to function d ### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: - There must be one space between the comment character and the content of the comment -- There must be a newline between a Kdoc andpressiding code +- There must be a newline between a Kdoc and presiding code - An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** From 3e72a95a8d8860eb09717c83cc7144331ed2f7b6 Mon Sep 17 00:00:00 2001 From: akuleshov7 Date: Mon, 7 Dec 2020 02:12:07 +0300 Subject: [PATCH 09/18] Codestyle ### What's done: Review notes --- info/guide/diktat-coding-convention.md | 379 ++++++++++++++++--------- info/guide/guide-chapter-1.md | 6 +- info/guide/guide-chapter-2.md | 2 +- info/guide/guide-chapter-3.md | 31 +- info/guide/guide-chapter-4.md | 95 ++++++- info/guide/guide-chapter-6.md | 12 +- info/guide/guide-chapter-8.md | 88 ------ 7 files changed, 364 insertions(+), 249 deletions(-) delete mode 100644 info/guide/guide-chapter-8.md diff --git a/info/guide/diktat-coding-convention.md b/info/guide/diktat-coding-convention.md index 7d1bf58ea3..4f4a3d9b97 100644 --- a/info/guide/diktat-coding-convention.md +++ b/info/guide/diktat-coding-convention.md @@ -20,7 +20,7 @@ For the code to be considered high-quality, it must entail the following charact Like other modern programming languages, Kotlin is an advanced programming language that complies with the following general principles: 1. Clarity — a necessary feature of programs that are easy to maintain and refactor. 2. Simplicity — a code is easy to understand and implement. -3. Consistency — enables a code to be easily modified, reviewed and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles.enables code to be easily modified, reviewed and understood by the team members. +3. Consistency — enables a code to be easily modified, reviewed, and understood by the team members. Unification is particularly important when the same team works on the same project, utilizing similar styles enabling a code to be easily modified, reviewed, and understood by the team members. Also, we need to consider the following factors when programming on Kotlin: @@ -28,8 +28,8 @@ Also, we need to consider the following factors when programming on Kotlin: Kotlin combines two of the main programming paradigms: functional and object-oriented. Both of these paradigms are trusted and well-known software engineering practices. - As a young programming language, Kotlin is built on the top of well-established languages such as Java, C++, C#, and Scala. - This enables Kotlin to introduce many features that help you write cleaner, more readable code, while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, when statements, much easier work with collections, type auto conversion, and other syntactic sugar. + As a young programming language, Kotlin is built on top of well-established languages such as Java, C++, C#, and Scala. + This enables Kotlin to introduce many features that help a developer write cleaner, more readable code while also reducing the number of complex code structures. For example, type and null safety, extension functions, infix syntax, immutability, val/var differentiation, expression-oriented features, "when" statements, much easier work with collections, type auto conversion, and other syntactic sugar. 2. Following Kotlin idioms @@ -59,11 +59,11 @@ Unless otherwise stated, this specification applies to versions 1.3 and later of ### Exceptions Even though exceptions may exist, it is essential to understand why rules and recommendations are needed. -Depending on your project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. +Depending on a project situation or personal habits, you can break some of the rules. However, remember that one exception may lead to many and eventually can destroy code consistency. As such, there should be very few exceptions. When modifying open-source code or third-party code, you can choose to use the code style from this open-source project (instead of using the existing specifications) to maintain consistency. Software that is directly based on the Android native operating system interface, such as the Android Framework, remains consistent with the Android style. # 1. Naming -In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps you clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations. +In programming, it is not always easy to meaningfully and appropriately name variables, functions, classes, etc. Using meaningful names helps to clearly express your code's main ideas and functionality and avoid misinterpretation, unnecessary coding and decoding, "magic" numbers, and inappropriate abbreviations. Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. @@ -76,7 +76,7 @@ For identifiers, use the following naming conventions: Explanation: Each valid identifier name should match the regular expression `\w{2,64}`. `{2,64}` means that the name length is 2 to 64 characters, and the length of the variable name should be proportional to its life range, functionality, and responsibility. Name lengths of less than 31 characters are generally recommended. However, this depends on the project. Otherwise, a class declaration with generics or inheritance from a superclass can cause line breaking. -No special prefix or suffix should be used in the names. The following examples are inappropriate: name_, mName, s_name, and kName. +No special prefix or suffix should be used in names. The following examples are inappropriate names: name_, mName, s_name, and kName. 2. Choose file names that would describe the content. Use camel case (PascalCase) and `.kt` extension. @@ -114,7 +114,7 @@ The only exception is function names in `Unit tests.` | n,h | h,n | nr, head, height | | rn, m | m,rn | mbr, item | -**Exceptions** +**Exceptions:** - The i,j,k variables used in loops are part of the industry standard. One symbol can be used for such variables. - The `e` variable can be used to catch exceptions in catch block: `catch (e: Exception) {}` - The Java community generally does not recommend the use of prefixes. However, when developing Android code, you can use the s and m prefixes for static and non-public non-static fields, respectively. @@ -130,15 +130,15 @@ Note that prefixing can also negatively affect the style and the auto-generation ### 1.2 Packages names -### Rule 1.2.1: Format of package names +### Rule 1.2.1: Package names dots Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. Each file should have a `package` directive. -Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product and module names, and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. +Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. **Exceptions:** - In certain cases, such as open-source projects or commercial cooperation, package names should not start with `your.company.domain.` -- If the package name starts with a number or other characters that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`. +- If the package name starts with a number or other character that cannot be used at the beginning of the Java/Kotlin package name, then underscores are allowed. For example: `com.example._123name`. - Underscores are sometimes permitted if the package name contains reserved Java/Kotlin keywords, such as `org.example.hyphenated_name`, `int_.example`. **Valid example**: @@ -178,7 +178,7 @@ class Order {} Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. -To name functions use the following formatting rules: +To name functions, use the following formatting rules: a) To get, modify, or calculate a certain value: get + non-boolean field(). Note that the Kotlin compiler automatically generates getters for some classes, applying the special syntax preferred for the 'get' fields: kotlin private val field: String get() { }. kotlin private val field: String get() { }. ```kotlin @@ -228,17 +228,17 @@ fun addKeyListener(Listener) Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. -1. Constants are attributes created with the const keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. +2. Constant names should contain only uppercase letters separated by underscores. They should have a `val` or `const val` (`const` should be used only with primitive types) modifier to make them final (immutable) explicitly. In most cases, if you need to specify a constant value, then you need to create it with the `const val` modifier. Note that not all `val` variables are constants. -2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to explicitly make them final. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. -3. Objects that have immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. +3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. 4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. + Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. You can avoid using magic numbers with the following method: - Using library functions and APIs. For example, instead of checking that `size == 0`, use `isEmpty()` function. To work with `time`, use built-ins from `java.time API`. -- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9) +- Enumerations can be used to name patterns. Refer to [Recommended usage scenario for enumeration in 3.9](#c3.9). **Invalid example**: @@ -258,7 +258,7 @@ const val String APPLICATION_NAME = "Launcher"; ### 1.6 Non-constant fields (variables) ### Rule 1.6.1: Non-constant field name Non-constant field names should use camel case and start with a lowercase letter. -A local variable cannot be treated as a constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. +A local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. For example: `var namesList: List` Names of non-constant variables should use `lowerCamelCase`. The name of the final immutable field used to store the singleton object can use the same camel case notation. @@ -278,7 +278,7 @@ val mutableCollection: MutableSet = HashSet() ### Rule 1.6.2: Boolean variable names with negative meaning -Avoid using Boolean variable names with negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". +Avoid using Boolean variable names with a negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". For instance, it is not easy to understand the meaning of !isNotError. The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes. However, not all methods returning Boolean type have this notation. @@ -336,13 +336,42 @@ Use a single-line form when you store the entire KDoc block in one line (and the ### Rule 2.1.1: KDoc is used for each public, protected or internal code element -At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). Other code blocks can also have KDocs if needed. -Instead of using comments before properties in class - use `@property` tag in a KDoc of a class. -All properties of the primary constructor should be also documented in a KDoc with a `@property` tag. +At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). +Other code blocks can also have KDocs if needed. +Instead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class. +All properties of the primary constructor should also be documented in a KDoc with a `@property` tag. + +**Incorrect example:** +```kotlin +/** + * Class description + */ +class Example( + /** + * property description + */ + val foo: Foo, + // another property description + val bar: Bar +) +``` + +**Correct example:** +```kotlin +/** + * Class description + * @property foo property description + * @property bar another property description + */ +class Example( + val foo: Foo, + val bar: Bar +) +``` **Exceptions:** -1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood. +1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood. 2. It is optional to add comments for simple one-line methods, such as shown in the example below: ```kotlin @@ -357,8 +386,6 @@ fun isEmptyList(list: List) = list.size == 0 ``` Note: You can skip KDocs for a method's override if it is almost the same as the superclass method. -### Rule 2.1.2: Describing methods with arguments, return value or can throw exceptions -When the method has arguments, return value, or can throw exceptions, it must be described in the KDoc block: with @param, @return, @throws ### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc. @@ -405,18 +432,20 @@ Therefore, Kdoc should contain the following: - `@apiNote`: Explain the API precautions, including whether to allow null and whether the method is thread-safe, as well as the algorithm complexity, input, and output range, exceptions, etc. - `@implNote`: A note related to API implementation, which implementers should keep in mind. - One empty line, followed by regular `@param`, `@return`, `@throws`, and other comments. -- The conventional standard "block labels" arranged in the following order: `@param`, `@return`, `@throws`. +- The conventional standard "block labels" are arranged in the following order: `@param`, `@return`, `@throws`. Kdoc should not contain: - Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space. - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. -If a tag block cannot be described in one line, you should indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). +If a tag block cannot be described in one line, indent the content of the new line by *four spaces* from the `@` position to achieve alignment (`@` counts as one + three spaces). + +**Exception:** -**Exception:** When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. +When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. See [3.8 Horizontal space](#c3.8). -In Kotlin, compared to Java, you are able to put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). +In Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag. **Examples:** @@ -429,7 +458,7 @@ This comment should contain @since tag. The right style is to write the applicat */ ``` -Other KDoc tags (such as @param type parameters and @see.) can be added as follow: +Other KDoc tags (such as @param type parameters and @see.) can be added as follows: ```kotlin /** * Description of functionality @@ -442,7 +471,7 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo ### 2.2 Comments to the file header ### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. -Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, you can subsequently add it in the same format. +Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format. The following examples for Huawei describe the format of the **copyright license**: \ Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \ @@ -453,7 +482,7 @@ Regarding the **release notes**, see examples below: - `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. These two years can be the same (for example, `2020–2020`). When the file is substantially changed (for example, through feature extensions and major refactorings), the subsequent years must be updated. -- The **copyright statement** can use your company's subsidiaries. For example: \ +- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \ Chinese version: `版权所有 (c) 海思半导体 2012-2020` \ English version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.` @@ -468,9 +497,9 @@ The following example is a copyright statement for Huawei, without other functio The following factors should be considered when writing the file header or comments for top-level classes: - File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline. -- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it. +- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. -- Do not include empty comment blocks.If there is no content after the option `@apiNote`, the entire tag block should be deleted. +- Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted. - The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. @@ -487,8 +516,8 @@ The function header comment's content is optional, but not limited to function d ### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: - There must be one space between the comment character and the content of the comment -- There must be a newline between a Kdoc and the pressiding code -- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). +- There must be a newline between a Kdoc and presiding code +- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** ```kotlin @@ -530,7 +559,7 @@ It is a good practice to add a blank line between the body of the comment and Kd ``` - Leave one single space between the comment on the right side of the code and the code. -If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes your code more understandable. +If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable. When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces. Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`. @@ -558,7 +587,7 @@ val someVal = if (nr % 15 == 0) { } ``` -- Start all comments (including KDoc) with a space after the first symbol (`//`, `/*`, `/**` and `*`) +- Start all comments (including KDoc) with space after the first symbol (`//`, `/*`, `/**` and `*`) **Valid example:** ```kotlin @@ -568,17 +597,17 @@ val x = 0 // this is a comment ### Rule 2.4.2: Do not comment on unused code blocks Do not comment on unused code blocks, including imports. Delete these code blocks immediately. A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose. -Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be properly maintained. -When you attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed. -The correct approach is to delete the unnecessary code directly and immediately when it is not used. +Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained. +In an attempt to reuse the code, there is a high probability that you will introduce defects that are easily missed. +The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. +### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. They should all have a unified style to facilitate the unified text search processing. -**For example**: +**Example**: ```kotlin // TODO(): Jira-XXX - support new json format // FIXME: Jira-XXX - fix NPE in this code block @@ -594,8 +623,9 @@ If the file is too long and complex, it should be split into smaller files, func It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. -### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. +### Rule 3.1.2: Code blocks in the source file should be separated by one blank line and should be in the proper order. A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. + a) Code blocks should be in the following order: 1. Kdoc for licensed or copyrighted files 2. `@file` annotation @@ -608,11 +638,11 @@ b) Each of the preceding code blocks should be separated by a blank line. c) Import statements are alphabetically arranged, without using line breaks and wildcards ( wildcard imports - `*`). -d) **Recommendation**: One `.kt` source file should contain only one class declaration, and its name should match the filename +d) **Recommendation**. One `.kt` source file should contain only one class declaration, and its name should match the filename e) Avoid empty files that do not contain the code or contain only imports/comments/package name -### Recommendation 3.1.3: Import statements order. +### Recommendation 3.1.3: Import statements order. From top to bottom, the order is the following: 1. Android @@ -642,11 +672,11 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. +### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. + Notes: -1. There should be no blank lines between properties. -**Exceptions**: When there is a comment before a property on a separate line or annotations on a separate line. +1. There should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line. 2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc. 3. Enum entries and constant properties (`const val`) in companion objects should be alphabetically arranged. @@ -710,12 +740,12 @@ if (condition) { Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces: - The opening brace and first line of the code block are on the same line. - The closing brace is on its own new line. -- The closing brace can be followed by a newline. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords. -These keywords should not be split from the closing brace by a newline. +- The closing brace can be followed by a newline character. The only exceptions are `else`, `finally`, and `while` (from `do-while` statement), or `catch` keywords. +These keywords should not be split from the closing brace by a newline character. **Exception cases**: -1) For lambdas, there is no need to put a newline after the first (function-related) opening brace. A newline should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)). +1) For lambdas, there is no need to put a newline character after the first (function-related) opening brace. A newline character should appear only after an arrow (`->`) (see [point 5 of Rule 3.6.2](#r3.6.2)). ```kotlin arg.map { value -> @@ -767,7 +797,7 @@ do { ### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces. Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted). -If you prefer using tabs, simply configure them to automatically change to spaces in your IDE. +If you prefer using tabs, simply configure them to change to spaces in your IDE automatically. These code blocks should be indented if they are placed on the new line, and the following conditions are met: - The code block is placed immediately after an opening brace - The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.) @@ -807,7 +837,7 @@ if (condition) ``` **Exceptions**: -- When breaking parameter list of a method/class constructor it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument: +- When breaking the parameter list of a method/class constructor, it can be aligned with `8 spaces`. A parameter that was moved to a new line can be on the same level as the previous argument: ```kotlin fun visit( @@ -826,7 +856,7 @@ val abcdef = "my splitted" + " string" ``` -- A list of supertypes should be indented with `4 spaces` if they are on different lines, or with `8 spaces` if the leading colon is also on a separate line +- A list of supertypes should be indented with `4 spaces` if they are on different lines or with `8 spaces` if the leading colon is also on a separate line ```kotlin class A : @@ -839,7 +869,7 @@ class A ### 3.4 Empty blocks -### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. +### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.) @@ -850,7 +880,7 @@ override fun foo() { } ``` -**Valid examples** (but note once again, that generally empty blocks are prohibited): +**Valid examples** (note once again that generally empty blocks are prohibited): ```kotlin fun doNothing() {} @@ -876,7 +906,7 @@ try { ### 3.5 Line length -### Recommendation 3.5.1: Line length should be less than 120 symbols. +### Recommendation 3.5.1: Line length should be less than 120 symbols. The international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: @@ -898,7 +928,7 @@ Each one of these characters represents two narrow characters. ### 3.6 Line breaks (newlines) -### Recommendation 3.6.1: Each line can have a maximum of one statement. +### Recommendation 3.6.1: Each line can have a maximum of one statement. Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** @@ -914,11 +944,11 @@ val b = "" ### Rule 3.6.2: Rules for line-breaking -1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline. +1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character. There should be no redundant semicolon at the end of the lines. -When a newline is needed to split the line, it should be placed after operators like `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). -However, the newline should be placed before operators such as `.`, `?.`, `?:`, and `::`. +When a newline character is needed to split the line, it should be placed after such operators as `&&`/`||`/`+`/etc. and all infix functions (for example, `xor`). +However, the newline character should be placed before operators such as `.`, `?.`, `?:`, and `::`. Note that all comparison operators, such as `==`, `>`, `<`, should not be split. @@ -959,7 +989,7 @@ if (condition) list.map { foo(it) }.filter { bar(it) } else list.drop(1) A brace should be placed immediately after the name without any spaces in declarations or at call sites. 4) Newlines should be placed right after the comma (`,`). 5) If a lambda statement contains more than one line in its body, a newline should be placed after an arrow if the lambda statement has explicit parameters. - If it uses an implicit parameter (`it`), the newline should be placed after the opening brace (`{`). + If it uses an implicit parameter (`it`), the newline character should be placed after the opening brace (`{`). The following examples illustrate this rule: @@ -1039,7 +1069,7 @@ class MyFavouriteVeryLongClassHolder : ### 3.7 Blank lines -### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size +### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. - Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). @@ -1059,7 +1089,7 @@ fun baz() { ### 3.8 Horizontal space -### Rule 3.8.1: Usage of whitespace for code separation +### Rule 3.8.1: Usage of whitespace for code separation **Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.) @@ -1099,7 +1129,7 @@ fun baz() { There should be no spaces before `,` , `:` and `;`. **Exceptions** for spaces and colons are the following: - - when `:` is used to separate a type and a super type, including an anonymous object (after object keyword) + - when `:` is used to separate a type and a supertype, including an anonymous object (after object keyword) - when delegating to a superclass constructor or different constructor of the same class **Valid example:** @@ -1113,7 +1143,7 @@ fun baz() { } ``` -6. There should be *only one space* between the identifier and it's type: `list: List` +6. There should be *only one space* between the identifier and its type: `list: List` If the type is nullable, there should be no space before `?`. 7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`. @@ -1130,15 +1160,15 @@ fun foo 9. Never put a space after `(`, `[`, `<` (when used as a bracket in templates) or before `)`, `]`, `>` (when used as a bracket in templates). -10. There should be no spaces between prefix/postfix operator (like `!!` or `++`), and it's an operand. +10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand. -### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. +### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. *Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because: - When modifying code, it takes much time for new developers to format, support, and fix alignment issues. - Long identifier names will break the alignment and lead to less presentable code. -- Alignment possesses more disadvantages than advantages. To reduce maintenance costs, misalignment is the best choice. +- There are more disadvantages than advantages in alignment. To reduce maintenance costs, the best choice is not to use horizontal alignment. Recommendation: Alignment only looks suitable for `enum class`, where it can be used in table format to improve code readability: ```kotlin @@ -1164,7 +1194,7 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean ### 3.9 Enumerations -### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. +### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. 1) Enum values are separated by a comma and a line break. `;` is put on the new line: ```kotlin enum class Warnings { @@ -1219,7 +1249,7 @@ Each property or variable must be declared on a separate line. val n1: Int; val n2: Int ``` -### Recommendation 3.10.2: Variables should be declared near the line where they are first used. +### Recommendation 3.10.2: Variables should be declared near the line where they are first used. Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. Local variables are usually initialized during their declaration or immediately after. The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure). @@ -1234,9 +1264,9 @@ The compiler can issue a warning when it is missing. ### 3.12 Annotations -### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. +### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. -1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line). +1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). **Valid example**: ```kotlin @@ -1261,7 +1291,7 @@ fun getNameIfPresent() { /* ... */ } ### 3.13 Layout of comments -### Recommendation 3.13.1: Block comments location. +### Recommendation 3.13.1: Block comments location. Block comments should be placed at the same indentation level as the surrounding code. See examples below. @@ -1281,7 +1311,7 @@ class SomeClass { ### 3.14 Modifiers and constant values -### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. +### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. **Valid sequence:** ```kotlin @@ -1306,7 +1336,7 @@ operator data ``` -### Recommendation 3.14.2: An underscore should separate long numerical values. +### Recommendation 3.14.2: An underscore should separate long numerical values. **Note:** Using underscores simplifies reading and helps to find errors in numeric constants. ```kotlin val oneMillion = 1_000_000 @@ -1321,7 +1351,7 @@ val bytes = 0b11010010_01101001_10010100_10010010 ### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: [String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) -As such, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines and you do not need to split them with newlines. +Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters. **Invalid example**: ```kotlin @@ -1351,7 +1381,7 @@ val someString = "$myArgument ${myArgument.foo()}" **Redundant string template** -In case string template contains only one variable - there is no need to use string template. Use this variable directly. +In case a string template contains only one variable - there is no need to use the string template. Use this variable directly. **Invalid example**: ```kotlin @@ -1380,13 +1410,13 @@ However, it will print the following value: `0.8999999999999999` Therefore, for precise calculations (for example, in finance or exact sciences), using such types as `Int`, `Long`, `BigDecimal`are recommended. The `BigDecimal` type should serve as a good choice. -**Invalid example:** \ +**Invalid example**: \ Float values containing more than six or seven decimal numbers will be rounded. ```kotlin val eFloat = 2.7182818284f // Float, will be rounded to 2.7182817 ``` -**Valid example** (when precise calculations are needed): +**Valid example**: (when precise calculations are needed): ```kotlin val income = BigDecimal("2.0") val expense = BigDecimal("1.1") @@ -1436,7 +1466,7 @@ However, in some scenarios with loops or accumulators, only `var`s are permitted ### 4.2 Types -### Recommendation 4.2.1: Use Contracts and smart cast as much as possible. +### Recommendation 4.2.1: Use Contracts and smart cast as much as possible. The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code. @@ -1454,10 +1484,9 @@ The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/ref } ``` -Also Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast. -Contracts are used and are very stable in `stdlib`. +Also, Kotlin 1.3 introduced [Contracts](https://kotlinlang.org/docs/reference/whatsnew13.html#contracts) that provide enhanced logic for smart-cast. +Contracts are used and are very stable in `stdlib`, for example: -For example: ```kotlin fun bar(x: String?) { @@ -1485,7 +1514,7 @@ fun foo(s: String?) { } ``` -### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. +### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. Type aliases provide alternative names for existing types. If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. @@ -1514,8 +1543,8 @@ typealias Predicate = (T) -> Boolean ### 4.3 Null safety and variable declarations Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. -### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. -To avoid `NullPointerException` and help compiler to prevent Null Poniter Exceptions, avoid using nullable types (with `?` symbol). +### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. +To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: ```kotlin @@ -1527,9 +1556,9 @@ val a: Int? = 0 val a: Int = 0 ``` -Nevertheless, if you use Java libraries extensively, you will have to use nullable types and enrich your code with `!!` and `?` symbols. +Nevertheless, when using Java libraries extensively, you have to use nullable types and enrich the code with `!!` and `?` symbols. Avoid using nullable types for Kotlin stdlib (declared in [official documentation](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin.collections/)). -Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null` use `emptyList()`. +Try to use initializers for empty collections. For example, if you want to initialize a list instead of `null`, use `emptyList()`. **Invalid example**: ```kotlin @@ -1541,7 +1570,7 @@ val a: List? = null val a: List = emptyList() ``` -### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. +### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: ```kotlin @@ -1560,23 +1589,110 @@ val myVariable = emptyMap() ```kotlin val myVariable: Map = emptyMap() ``` + +### Null-safety +### 4.3.3 Explicit null checks + +Try to avoid explicit null checks (explicit comparison with `null`) +Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. +However, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin. + +There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c + +**Invalid example:** +```kotlin +// example 1 +var myVar: Int? = null +if (myVar == null) { + println("null") + return +} + +// example 2 +if (myVar != null) { + println("not null") + return +} + +// example 3 +val anotherVal = if (myVar != null) { + println("not null") + 1 + } else { + 2 + } +// example 4 +if (myVar == null) { + println("null") +} else { + println("not null") +} +``` + +**Valid example:** +```kotlin +// example 1 +var myVar: Int? = null +myVar?: run { + println("null") + return +} + +// example 2 +myVar?.let { + println("not null") + return +} + +// example 3 +val anotherVal = myVar?.also { + println("not null") + 1 + } ?: 2 + +// example 4 +myVar?.let { + println("null") +} ?: run { println("not null") } +``` + +**Exceptions:** + +In the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`. + +**Valid examples:** + +```kotlin +if (myVar != null) { + println("not null") +} else if (anotherCondition) { + println("Other condition") +} +``` + +```kotlin +if (myVar == null || otherValue == 5 && isValid) {} +``` + +Please also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`. + # 5. Functions ### 5.1 Function design -You can write clean code by gaining knowledge of how to build design patterns and avoid code smells. -You should utilize this approach, along with functional style, when you write Kotlin code. +Developers can write clean code by gaining knowledge of how to build design patterns and avoid code smells. +You should utilize this approach, along with functional style, when writing Kotlin code. The concepts behind functional style are as follows: Functions are the smallest unit of combinable and reusable code. They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code. The code in functions should be simple and not conceal the author's original intentions. -Additionally, it should have a clean abstraction, and control statements should be used in a straightforward manner. -The side effects (code that does not affect a function's return value, but affects global/object instance variables) should not be used for state changes of an object. +Additionally, it should have a clean abstraction, and control statements should be used straightforwardly. +The side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object. The only exceptions to this are state machines. Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. -In addition, standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. +Also, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments (???). As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input. -The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, and each step features the following characteristics: +The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics: 1. Simplicity 2. Verifiability 3. Testability @@ -1590,25 +1706,25 @@ There can be only one side effect in this data stream, which can be placed only ### Rule 5.1.1: Avoid functions that are too long. The function should be displayable on one screen and only implement one certain logic. -If a function is too long, it often means that it is complex and be split or made more primitive. Functions should consist of 30 lines (non-empty and non-comment) in total. +If a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total. **Exception:** Some functions that implement complex algorithms may exceed 30 lines due to aggregation and comprehensiveness. Linter warnings for such functions **can be suppressed**. Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else. -Therefore, it is recommended that you split such functions into several separate and shorter functions that are easier to manage. +Therefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage. This approach will enable other programmers to read and modify the code properly. ### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels. The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when). Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops). -**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function wheres the nesting levels of enclosing methods are not accumulated. +**Exception:** The nesting levels of the lambda expressions, local classes, and anonymous classes in functions are calculated based on the innermost function. The nesting levels of enclosing methods are not accumulated. Functional decomposition should be implemented to avoid confusion for the developer who reads the code. -This will help the reader switch between context. +This will help the reader switch between contexts. ### Rule 5.1.3: Avoid using nested functions. Nested functions create a more complex function context, thereby confusing readers. -With nested functions the visibility context may not be evident to the code reader. +With nested functions, the visibility context may not be evident to the code reader. **Invalid example**: ```kotlin @@ -1624,7 +1740,7 @@ fun foo() { ### 5.2 Function arguments ### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list. -With such notation, it is easier to use curly brackets, which in turn leads to better code readability. +With such notation, it is easier to use curly brackets, leading to better code readability. **Valid example**: ```kotlin @@ -1642,12 +1758,12 @@ println("hey") ### Rule 5.2.2: Number of function parameters should be limited to 5 A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code. -It is recommended that you reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. +It is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class. It is recommended that you use Data Classes and Maps to unify these function arguments. ### Rule 5.2.3 Use default values for function arguments instead of overloading them -In Java, default values for function arguments are prohibited. That is why when you need to create a function with fewer arguments, the function should be overloaded. +In Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments. In Kotlin, you can use default arguments instead. **Invalid example**: @@ -1671,7 +1787,7 @@ private fun foo() { ### 6.1 Classes ### Rule 6.1.1: When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. -In case class contains only one explicit constructor - it should be converted to a primary constructor. +In case the class contains only one explicit constructor - it should be converted to a primary constructor. **Invalid example**: ```kotlin @@ -1689,14 +1805,14 @@ class Test(var a: Int) { // ... } -// in case of any annotations or modifiers used on constructor: +// in case of any annotations or modifiers used on a constructor: class Test private constructor(var a: Int) { // ... } ``` ### Rule 6.1.2: Prefer data classes instead of classes without any functional logic. -Some people say that the data class is a code smell. But if you need to use it, and as a result, your code is becoming more simple, you can use Kotlin `data class`. The main purpose of this class is to hold data, +Some people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data, but also `data class` will automatically generate several useful methods: - equals()/hashCode() pair; - toString() @@ -1737,12 +1853,12 @@ class Test() { data class Test1(var a: Int = 0, var b: Int = 0) ``` -**Exception #1**: Note, that data classes cannot be abstract, open, sealed or inner, that's why these types of classes cannot be changed to a data class. +**Exception 1**: Note that data classes cannot be abstract, open, sealed, or inner; that is why these types of classes cannot be changed to a data class. -**Exception #2**: No need to convert a class to data class if this class extends some other class or implements an interface. +**Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface. ### Rule 6.1.3: Do not use the primary constructor if it is empty or useless. -The primary constructor is a part of the class header; it goes after the class name and (optional) type parameters but can be omitted if it is useless. +The primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used. **Invalid example**: ```kotlin @@ -1752,7 +1868,7 @@ class Test() { var b: Int = 0 } -// empty primary constructor is not needed here also +// empty primary constructor is not needed here // it can be replaced with a primary contructor with one argument or removed class Test() { var a = "Property" @@ -1769,7 +1885,7 @@ class Test() { **Valid example**: ```kotlin -// the good example here is a data class, but this example shows that you should get rid of braces for primary constructor +// the good example here is a data class; this example also shows that you should get rid of braces for the primary constructor class Test { var a: Int = 0 var b: Int = 0 @@ -1777,12 +1893,11 @@ class Test { ``` ### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class. -The primary constructor cannot contain any code. That's why Kotlin has introduced `init` blocks. -These blocks are used to store the code that should be run during the initialization of the class. -Kotlin allows writing multiple initialization blocks that are executed in the same order as they appear in the class body. +The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks. +These blocks store the code to be run during the class initialization. +Kotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body. Even when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code. -So in your code, you should try to use a single `init` block to reduce the complexity. In case you need to do some logging or make some calculations before the assignment -of some class property, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and +Therefore, you should try to use a single `init` block to reduce the code's complexity. . If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin. **Invalid example**: @@ -1815,7 +1930,7 @@ class YourClass(var name: String) { ``` The `init` block was not added to Kotlin to help you initialize your properties; it is needed for more complex tasks. -Therefore if the `init` block contains only assignments of variables - move it directly to properties, so that they will be correctly initialized near the declaration. +Therefore if the `init` block contains only assignments of variables - move it directly to properties to be correctly initialized near the declaration. In some cases, this rule can be in clash with [6.1.1](#r6.1.1), but that should not stop you. **Invalid example**: @@ -1836,7 +1951,7 @@ class A(baseUrl: String) { ``` ### Rule 6.1.5: Explicit supertype qualification should not be used if there is not clash between called methods. -This rule is applicable for both interfaces and classes. +This rule is applicable to both interfaces and classes. **Invalid example**: ```kotlin @@ -1895,12 +2010,12 @@ val table: Map } ``` -In this case the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. +In this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. It is one of the exceptions from the [identifier names rule](#r1.2) ### Recommendation 6.1.8: avoid using custom getters and setters. Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields). -Kotlin compiler automatically generates `get` and `set` methods for properties and also provides the possibility to override it. +Kotlin compiler automatically generates `get` and `set` methods for properties and can override them. **Invalid example:** ```kotlin @@ -1939,7 +2054,7 @@ class A { **Exception:** `Private setters` are only exceptions that are not prohibited by this rule. ### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug). -If you have ignored [recommendation 6.1.8](#r6.1.8) you should be careful with using the name of the property in your custom getter/setter +If you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead. **Invalid example (very bad)**: @@ -1952,10 +2067,10 @@ var isEmpty: Boolean get() = isEmpty ``` -### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. +### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. In Java, trivial getters - are the getters that are just returning the field value. Trivial setters - are merely setting the field with a value without any transformation. -However, in Kotlin, trivial getters/setters are generated by the default. There is no need to use it explicitly for all types of data structures in Kotlin. +However, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin. **Invalid example**: ```kotlin @@ -1979,8 +2094,8 @@ class A { } ``` -### Rule 6.1.11: use apply for grouping object initialization. -In Java, before functional programming became popular, many classes from common libraries used configuration paradigm. +### Rule 6.1.11: use apply for grouping object initialization. +In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -2032,11 +2147,11 @@ fun main() { It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy. Extension functions are resolved statically. -### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. +### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer. -### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). +### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. This can lead to an issue when an incorrect method is used. And that can lead to an issue when incorrect method is used. @@ -2067,9 +2182,9 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects -### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. +### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. -This allows you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. +This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. **Invalid example**: ```kotlin @@ -2090,8 +2205,8 @@ fun String.stringInfo(): Int { "myStr".stringInfo() ``` -### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. -Kotlin’s objects are extremely useful when you need to implement some interface from an external library that doesn’t have any state. +### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. +Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. **Valid example**: @@ -2103,4 +2218,4 @@ interface I { object O: I { override fun foo() {} } -``` +``` \ No newline at end of file diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 62c53a80e6..b7aa51c86d 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -5,7 +5,7 @@ Note: The source file encoding format (including comments) must be UTF-8 only. T ### 1.1 Identifier names -### 1.1.1: Identifiers naming conventions +### Rule 1.1.1: Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. @@ -164,12 +164,12 @@ fun addKeyListener(Listener) Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. -1. Constants are attributes created with the const keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant value that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. If an object state can be changed, the value is not a constant. +2. Constant names should contain only uppercase letters separated by underscores. They should have a `val` or `const val` (`const` should be used only with primitive types) modifier to make them final (immutable) explicitly. In most cases, if you need to specify a constant value, then you need to create it with the `const val` modifier. Note that not all `val` variables are constants. -2. Constant names should contain only uppercase letters separated by underscores. They should have a `val` or `const val` modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the `const val` modifier. Note that not all `val` variables are constants. 3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. 4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. + Magic constants like `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. These constants typically represent business logic values, such as measures, capacity, scope, location, tax rate, promotional discounts, and power base multiples in algorithms. You can avoid using magic numbers with the following method: diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index ec1fb46c01..7bda1d751f 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -298,7 +298,7 @@ In an attempt to reuse the code, there is a high probability that you will intro The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. +### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. They should all have a unified style to facilitate the unified text search processing. diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index a087e57516..fd50adad18 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -7,7 +7,7 @@ If the file is too long and complex, it should be split into smaller files, func It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. -### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. +### Rule 3.1.2: Code blocks in the source file should be separated by one blank line and should be in the proper order. A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. a) Code blocks should be in the following order: @@ -26,7 +26,7 @@ d) **Recommendation**. One `.kt` source file should contain only one class decla e) Avoid empty files that do not contain the code or contain only imports/comments/package name -### Recommendation 3.1.3: Import statements order. +### Recommendation 3.1.3: Import statements order. From top to bottom, the order is the following: 1. Android @@ -56,8 +56,9 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. +### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. + Notes: 1. There should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line. 2. Properties with comments/Kdoc should be separated by a newline before the comment/Kdoc. @@ -252,7 +253,7 @@ class A ### 3.4 Empty blocks -### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. +### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.) @@ -289,7 +290,7 @@ try { ### 3.5 Line length -### Recommendation 3.5.1: Line length should be less than 120 symbols. +### Recommendation 3.5.1: Line length should be less than 120 symbols. The international code style prohibits `non-Latin` (`non-ASCII`) symbols. (See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: @@ -311,7 +312,7 @@ Each one of these characters represents two narrow characters. ### 3.6 Line breaks (newlines) -### Recommendation 3.6.1: Each line can have a maximum of one statement. +### Recommendation 3.6.1: Each line can have a maximum of one statement. Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** @@ -452,7 +453,7 @@ class MyFavouriteVeryLongClassHolder : ### 3.7 Blank lines -### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size +### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. - Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). @@ -472,7 +473,7 @@ fun baz() { ### 3.8 Horizontal space -### Rule 3.8.1: Usage of whitespace for code separation +### Rule 3.8.1: Usage of whitespace for code separation **Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.) @@ -545,7 +546,7 @@ fun foo 10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand. -### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. +### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. *Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because: @@ -577,7 +578,7 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean ### 3.9 Enumerations -### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. +### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. 1) Enum values are separated by a comma and a line break. `;` is put on the new line: ```kotlin enum class Warnings { @@ -632,7 +633,7 @@ Each property or variable must be declared on a separate line. val n1: Int; val n2: Int ``` -### Recommendation 3.10.2: Variables should be declared near the line where they are first used. +### Recommendation 3.10.2: Variables should be declared near the line where they are first used. Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. Local variables are usually initialized during their declaration or immediately after. The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure). @@ -647,7 +648,7 @@ The compiler can issue a warning when it is missing. ### 3.12 Annotations -### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. +### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. 1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). @@ -674,7 +675,7 @@ fun getNameIfPresent() { /* ... */ } ### 3.13 Layout of comments -### Recommendation 3.13.1: Block comments location. +### Recommendation 3.13.1: Block comments location. Block comments should be placed at the same indentation level as the surrounding code. See examples below. @@ -694,7 +695,7 @@ class SomeClass { ### 3.14 Modifiers and constant values -### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. +### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. **Valid sequence:** ```kotlin @@ -719,7 +720,7 @@ operator data ``` -### Recommendation 3.14.2: An underscore should separate long numerical values. +### Recommendation 3.14.2: An underscore should separate long numerical values. **Note:** Using underscores simplifies reading and helps to find errors in numeric constants. ```kotlin val oneMillion = 1_000_000 diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index 5485ceab75..2f039c804e 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -72,7 +72,7 @@ However, in some scenarios with loops or accumulators, only `var`s are permitted ### 4.2 Types -### Recommendation 4.2.1: Use Contracts and smart cast as much as possible. +### Recommendation 4.2.1: Use Contracts and smart cast as much as possible. The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code. @@ -120,7 +120,7 @@ fun foo(s: String?) { } ``` -### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. +### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. Type aliases provide alternative names for existing types. If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. @@ -149,7 +149,7 @@ typealias Predicate = (T) -> Boolean ### 4.3 Null safety and variable declarations Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. -### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. +### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: @@ -176,7 +176,7 @@ val a: List? = null val a: List = emptyList() ``` -### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. +### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: ```kotlin @@ -195,3 +195,90 @@ val myVariable = emptyMap() ```kotlin val myVariable: Map = emptyMap() ``` + +### Null-safety +### 4.3.3 Explicit null checks + +Try to avoid explicit null checks (explicit comparison with `null`) +Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. +However, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin. + +There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c + +**Invalid example:** +```kotlin +// example 1 +var myVar: Int? = null +if (myVar == null) { + println("null") + return +} + +// example 2 +if (myVar != null) { + println("not null") + return +} + +// example 3 +val anotherVal = if (myVar != null) { + println("not null") + 1 + } else { + 2 + } +// example 4 +if (myVar == null) { + println("null") +} else { + println("not null") +} +``` + +**Valid example:** +```kotlin +// example 1 +var myVar: Int? = null +myVar?: run { + println("null") + return +} + +// example 2 +myVar?.let { + println("not null") + return +} + +// example 3 +val anotherVal = myVar?.also { + println("not null") + 1 + } ?: 2 + +// example 4 +myVar?.let { + println("null") +} ?: run { println("not null") } +``` + +**Exceptions:** + +In the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`. + +**Valid examples:** + +```kotlin +if (myVar != null) { + println("not null") +} else if (anotherCondition) { + println("Other condition") +} +``` + +```kotlin +if (myVar == null || otherValue == 5 && isValid) {} +``` + +Please also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`. + diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index 4760a7e0f5..0ebbd3754c 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -282,7 +282,7 @@ var isEmpty: Boolean get() = isEmpty ``` -### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. +### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. In Java, trivial getters - are the getters that are just returning the field value. Trivial setters - are merely setting the field with a value without any transformation. However, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin. @@ -309,7 +309,7 @@ class A { } ``` -### Rule 6.1.11: use apply for grouping object initialization. +### Rule 6.1.11: use apply for grouping object initialization. In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -362,11 +362,11 @@ fun main() { It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy. Extension functions are resolved statically. -### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. +### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer. -### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). +### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. This can lead to an issue when an incorrect method is used. And that can lead to an issue when incorrect method is used. @@ -397,7 +397,7 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects -### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. +### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. @@ -420,7 +420,7 @@ fun String.stringInfo(): Int { "myStr".stringInfo() ``` -### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. +### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. diff --git a/info/guide/guide-chapter-8.md b/info/guide/guide-chapter-8.md deleted file mode 100644 index 76b3d9c9f2..0000000000 --- a/info/guide/guide-chapter-8.md +++ /dev/null @@ -1,88 +0,0 @@ -# 8. Things that will be moved to a main guide later - -### Null-safety -### 4.3.3 Explicit null checks - -Try to avoid explicit null checks (explicit comparison with `null`) -Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. -However, Kotlin architects wanted Kotlin to be fully compatible with Java; that's why the `null` keyword was also introduced in Kotlin. - -There are several code-structures that can be used in Kotlin to avoid null-checks. For example: `?:`, `.let {}`, `.also {}`, e.t.c - -**Invalid example:** -```kotlin -// example 1 -var myVar: Int? = null -if (myVar == null) { - println("null") - return -} - -// example 2 -if (myVar != null) { - println("not null") - return -} - -// example 3 -val anotherVal = if (myVar != null) { - println("not null") - 1 - } else { - 2 - } -// example 4 -if (myVar == null) { - println("null") -} else { - println("not null") -} -``` - -**Valid example:** -```kotlin -// example 1 -var myVar: Int? = null -myVar?: run { - println("null") - return -} - -// example 2 -myVar?.let { - println("not null") - return -} - -// example 3 -val anotherVal = myVar?.also { - println("not null") - 1 - } ?: 2 - -// example 4 -myVar?.let { - println("null") -} ?: run { println("not null") } -``` - -**Exceptions:** - -In the case of complex expressions, such as multiple `else-if` structures or long conditional statements, there is common sense to use explicit comparison with `null`. - -**Valid examples:** - -```kotlin -if (myVar != null) { - println("not null") -} else if (anotherCondition) { - println("Other condition") -} -``` - -```kotlin -if (myVar == null || otherValue == 5 && isValid) {} -``` - -Please also note, that instead of using `require(a != null)` with a not null check - you should use a special Kotlin function called `requireNotNull(a)`. - From 40dfe318c5f3002b4f1a092d07a0c9072a3adf37 Mon Sep 17 00:00:00 2001 From: akuleshov7 Date: Mon, 7 Dec 2020 02:13:59 +0300 Subject: [PATCH 10/18] Codestyle ### What's done: Review notes --- info/guide/diktat-coding-convention.md | 19 +++++++++++++++++++ info/guide/table-of-content.md | 2 +- 2 files changed, 20 insertions(+), 1 deletion(-) diff --git a/info/guide/diktat-coding-convention.md b/info/guide/diktat-coding-convention.md index 4f4a3d9b97..49a71cc5ec 100644 --- a/info/guide/diktat-coding-convention.md +++ b/info/guide/diktat-coding-convention.md @@ -1,3 +1,22 @@ + + +# Diktat Coding Convention + +### Content + +| Chapter | Content | +| ------------------- | ------------------------------------------------------------ | +| [0. Preface](#c0.1) | [Purpose](#c0.1), [General principles](#c0.2), [Terminology](#c0.3), [Exceptions](#c0.4) | +| [1. Naming](#c1) | [Identifiers](#c1.1), [Package names](#c1.2), [Classes, enumeration and interfaces](#c1.3), [Functions](#c1.4), [Constants](#c1.5), [Variables](#c1.6) | +| [2. Docs](#c2) | [Kdoc](#c2.1), [File header](#c2.2), [Comments on function header ](#c2.3), [Code comments](#c2.4) | +| [3. General formatting](#c3) | [File-related rules](#c3.1), [Braces](#c3.2), [Indentation](#c3.3), [Empty blocks](#c3.4), [Line length](#c3.5), [Line breaks (newlines)](#c3.6), [Blank lines](#c3.7), [Horizontal space](#c3.8), [Enumerations](#c3.9), [Variable declaration](#c3.10), [When expression](#c3.11), [Annotations](#c3.12), [Layout of comments](#c3.13), [Modifiers and constant values](#c3.14), [Strings](#c3.15)| +| [4. Variables and types](#c4) | [Variables](#c4.1), [Types](#c4.2), [Null safety and variable declarations](#4.3)| +| [5. Functions](#c5) | [Function design](#c5.1), [Function arguments](#c5.2)| +| [6. Classes](#c6) | [Classes](#c6.1), [Extension functions](#c6.2), [Interfaces](#c6.3), [Objects](#c6.4) | +| [7. Kotlin & Java](#c7) | | + + + ## Preface ### Purpose of this document diff --git a/info/guide/table-of-content.md b/info/guide/table-of-content.md index 55ce33a5fd..1e17d8eeb6 100644 --- a/info/guide/table-of-content.md +++ b/info/guide/table-of-content.md @@ -13,5 +13,5 @@ | [4. Variables and types](#c4) | [Variables](#c4.1), [Types](#c4.2), [Null safety and variable declarations](#4.3)| | [5. Functions](#c5) | [Function design](#c5.1), [Function arguments](#c5.2)| | [6. Classes](#c6) | [Classes](#c6.1), [Extension functions](#c6.2), [Interfaces](#c6.3), [Objects](#c6.4) | -| [7. Kotlin & Java](#c7) | [Classes](#c6.1), [Extension functions](#c6.2), [Interfaces](#c6.3), [Objects](#c6.4) | +| [7. Kotlin & Java](#c7) | | From ea3ecd9a25f6b198538e9dfa6210f7b8676b0974 Mon Sep 17 00:00:00 2001 From: vtchem Date: Mon, 7 Dec 2020 14:54:03 +0300 Subject: [PATCH 11/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-chapter-1.md | 20 +++-- info/guide/guide-chapter-2.md | 156 +++++++++++++++++++--------------- info/guide/guide-chapter-3.md | 89 ++++++++++--------- info/guide/guide-chapter-4.md | 21 +++-- info/guide/guide-chapter-5.md | 18 ++-- info/guide/guide-chapter-6.md | 55 ++++++------ info/guide/guide-chapter-8.md | 4 +- 7 files changed, 203 insertions(+), 160 deletions(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 7b3db3d42d..d330b34767 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -5,7 +5,8 @@ Note: The source file encoding format (including comments) must be UTF-8 only. T ### 1.1 Identifier names -### 1.1.1: Identifiers naming conventions +This section describes the general rules for naming identifiers. +### 1.1.1 Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. @@ -66,7 +67,8 @@ Note that prefixing can also negatively affect the style and the auto-generation ### 1.2 Packages names -### Rule 1.2.1: Package names dots + +### Rule 1.2.1 Package names dots Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. Each file should have a `package` directive. Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. @@ -84,7 +86,8 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces -### Rule 1.3.1: Classes, enumerations, interface names use Camel case +This section describes the general rules for naming classes, enumerations, and interfaces +### 1.3.1 Classes, enumerations, interface names use Camel case Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below: 1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`). @@ -110,7 +113,8 @@ class Order {} ### 1.4 Functions -### Rule 1.4.1: Function names should be in camel case +This section describes the general rules for naming functions. +### 1.4.1 Function names should be in camel case Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. @@ -160,7 +164,8 @@ fun addKeyListener(Listener) 2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. ### 1.5 Constants -### Rule 1.5.1 Constant names should be in UPPER case, words in the name are separated by underscore +This section describes the general rules for naming constraints. +### 1.5.1 Using UPPER case and underscore characters in a constraint name Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. @@ -192,7 +197,8 @@ const val String APPLICATION_NAME = "Launcher"; ### 1.6 Non-constant fields (variables) -### Rule 1.6.1: Non-constant field name +This section describes the general rules for naming variables. +### 1.6.1 Non-constant field name Non-constant field names should use camel case and start with a lowercase letter. A local variable cannot be treated as constant even if it is final and immutable. Therefore, it should not use the preceding rules. Names of collection type variables (sets, lists, etc.) should contain plural nouns. For example: `var namesList: List` @@ -212,7 +218,7 @@ val users: List = listOf(); val mutableCollection: MutableSet = HashSet() ``` -### Rule 1.6.2: Boolean variable names with negative meaning +### 1.6.2 Boolean variable names with negative meaning Avoid using Boolean variable names with a negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". For instance, it is not easy to understand the meaning of !isNotError. diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 75b2a95cfc..12ccdfbbd8 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -1,4 +1,4 @@ -# 2. Comments +# 2. Comments The best practice is to begin your code with a summary, which can be one sentence. Try to balance between writing no comments at all and obvious commentary statements for each line of code. @@ -8,8 +8,8 @@ Comments should accurately reflect the code's design ideas and logic and further As a result, other programmers will be able to save time when trying to understand the code. Imagine that you are writing the comments to help yourself to understand the original ideas behind the code in the future. -### 2.1 General form of Kdoc - +### 2.1 General form of Kdoc + KDoc is a combination of JavaDoc's block tags syntax (extended to support specific constructions of Kotlin) and Markdown's inline markup. The basic format of KDoc is shown in the following example: @@ -21,23 +21,27 @@ The basic format of KDoc is shown in the following example: fun method(arg: String) { // … } + ``` It is also shown in the following single-line form: ```kotlin /** Short form of KDoc. */ + ``` + Use a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html). -### Rule 2.1.1: KDoc is used for each public, protected or internal code element +#### 2.1.1 Using KDoc for the public, protected, or internal code elements At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). Other code blocks can also have KDocs if needed. Instead of using comments or KDocs before properties in the primary constructor of a class - use `@property` tag in a KDoc of a class. All properties of the primary constructor should also be documented in a KDoc with a `@property` tag. -**Incorrect example:** +*Incorrect example:* + ```kotlin /** * Class description @@ -52,7 +56,8 @@ class Example( ) ``` -**Correct example:** +*Correct exam****ple:* + ```kotlin /** * Class description @@ -67,13 +72,9 @@ class Example( **Exceptions:** -1. For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood. - -2. It is optional to add comments for simple one-line methods, such as shown in the example below: -```kotlin -val isEmpty: Boolean - get() = this.size == 0 -``` +* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood. + +* It is optional to add comments for simple one-line methods, such as shown in the example below: or @@ -81,44 +82,47 @@ or fun isEmptyList(list: List) = list.size == 0 ``` -Note: You can skip KDocs for a method's override if it is almost the same as the superclass method. +**Note:** You can skip KDocs for a method's override if it is almost the same as the superclass method. -### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc. +#### 2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block -**Valid examples**: +When the method has such details as arguments, return value, or can throw exceptions, it must be described in the KDoc block (with @param, @return, @throws, etc.). - ```kotlin +**Valid examples:** + +```kotlin /** - * This is the short overview comment for the example interface. - * / * Add a blank line between the comment text and each KDoc tag underneath * / - * @since 2019-01-01 - */ - protected abstract class Sample { +* This is the short overview comment for the example interface. +* / * Add a blank line between the comment text and each KDoc tag underneath * / +* @since 2019-01-01 +*/ +protected abstract class Sample { + /** + * This is a long comment with whitespace that should be split in + * comments on multiple lines when the line comment formatting is enabled. + * / * Add a blank line between the comment text and each KDoc tag underneath * / + * @param fox A quick brown fox jumps over the lazy dog + * @return battle between fox and dog + */ + protected abstract fun foo(Fox fox) /** - * This is a long comment with whitespace that should be split in - * comments on multiple lines in case the line comment formatting is enabled. + * These possibilities include: Formatting of header comments * / * Add a blank line between the comment text and each KDoc tag underneath * / - * @param fox A quick brown fox jumps over the lazy dog - * @return battle between fox and dog + * @return battle between fox and dog + * @throws ProblemException if lazy dog wins */ - protected abstract fun foo(Fox fox) - /** - * These possibilities include: Formatting of header comments - * / * Add a blank line between the comment text and each KDoc tag underneath * / - * @return battle between fox and dog - * @throws ProblemException if lazy dog wins - */ - protected fun bar() throws ProblemException { - // Some comments / * No need to add a blank line here * / - var aVar = ... + protected fun bar() throws ProblemException { + // Some comments / * No need to add a blank line here * / + var aVar = ... - // Some comments / * Add a blank line before the comment * / - fun doSome() - } - } + // Some comments / * Add a blank line before the comment * / + fun doSome() + } +} ``` -### Rule 2.1.3: Only one space between the Kdoc tag and content. Tags are arranged in the order. +#### 2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order. + There should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws. Therefore, Kdoc should contain the following: @@ -133,13 +137,13 @@ Kdoc should not contain: - Empty descriptions in tag blocks. It is better not to write Kdoc than waste code line space. - There should be no empty lines between the method/class declaration and the end of Kdoc (`*/` symbols). Important note: KDoc does not support the `@deprecated` tag. Instead, use the `@Deprecated` annotation. - + If a tag block cannot be described in one line, indent the content of the new line by `four spaces` from the `@` position to achieve alignment (`@` counts as one + three spaces). - + **Exception:** - + When the descriptive text in a tag block is too long to wrap, you can indent the alignment with the descriptive text in the last line. The descriptive text of multiple tags does not need to be aligned. -See [3.8 Horizontal space](#c3.8). +See <>. In Kotlin, compared to Java, you can put several classes inside one file, so each class should have a Kdoc formatted comment (as stated in rule 2.1). This comment should contain @since tag. The right style is to write the application version when its functionality is released. It should be entered after the `@since` tag. @@ -152,9 +156,11 @@ This comment should contain @since tag. The right style is to write the applicat * * @since 1.6 */ + ``` Other KDoc tags (such as @param type parameters and @see.) can be added as follows: + ```kotlin /** * Description of functionality @@ -164,25 +170,29 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo * @since 1.6 */ ``` -### 2.2 Comments to the file header -### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. -Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format. +### 2.2 Adding comments on the file header + +This section describes the general rules of adding comments on the file header. -The following examples for Huawei describe the format of the **copyright license**: \ +Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management). Also, describe the content inside files that contain multiple or no classes. + +Place comments on the file header before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format. + +The following examples for Huawei describe the format of the *copyright license*: \ Chinese version: `版权所有 (c) 华为技术有限公司 2012-2020` \ English version: `Copyright (c) Huawei Technologies Co., Ltd. 2012-2020. All rights reserved.` -Regarding the **release notes**, see examples below: +Regarding the *release notes*, see examples below: -- `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. +* `2012-2020` can be modified according to your actual situation. `2012` and `2020` are the years the file was first created and last modified, respectively. These two years can be the same (for example, `2020–2020`). When the file is substantially changed (for example, through feature extensions and major refactorings), the subsequent years must be updated. -- The **copyright statement** can use your company's subsidiaries, as shown in the below examples: \ +* The *copyright statement* can use your company's subsidiaries, as shown in the below examples: \ Chinese version: `版权所有 (c) 海思半导体 2012-2020` \ English version: `Copyright (c) Hisilicon Technologies Co., Ltd. 2012-2020. All rights reserved.` -- The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file. +* The copyright information should not be written in KDoc style or use single-line comments. It must start from the beginning of the file. The following example is a copyright statement for Huawei, without other functional comments: ```kotlin @@ -196,12 +206,11 @@ The following factors should be considered when writing the file header or comme - Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. - Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted. -- The industry practice is not to include historical information in comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. - +- The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. ### 2.3 Comments on the function header -### Rule 2.3.1: Do not make unnecessary and useless comments. -Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding [KDoc](#c2.1) style rules. + +Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding <> style rules. As stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name. Avoid unnecessary comments on dummy coding. @@ -209,13 +218,19 @@ Avoid unnecessary comments on dummy coding. The function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc. ### 2.4 Code comments -### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. + +This section describes the general rules of adding code comments. + +#### 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks. + It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: -- There must be one space between the comment character and the content of the comment -- There must be a newline between a Kdoc andpressiding code -- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). + +1. There must be one space between the comment character and the content of the comment. +2. There must be a newline between a Kdoc and presiding code. +3. An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** + ```kotlin /** * This is the short overview comment for the example interface. @@ -254,7 +269,7 @@ It is a good practice to add a blank line between the body of the comment and Kd } ``` -- Leave one single space between the comment on the right side of the code and the code. +4. Leave one single space between the comment on the right side of the code and the code. If you use conditional comments in the `if-else-if` scenario, put the comments inside the `else-if` branch or in the conditional block, but not before the `else-if`. This makes the code more understandable. When the if-block is used with curly braces, the comment should be placed on the next line after opening the curly braces. Compared to Java, the `if` statement in Kotlin statements returns a value. For this reason, a comment block can describe a whole `if-statement`. @@ -262,6 +277,7 @@ Compared to Java, the `if` statement in Kotlin statements returns a value. For t **Valid examples:** ```kotlin + val foo = 100 // right-side comment val bar = 200 /* right-side comment */ @@ -283,14 +299,16 @@ val someVal = if (nr % 15 == 0) { } ``` -- Start all comments (including KDoc) with space after the first symbol (`//`, `/*`, `/**` and `*`) +5. Start all comments (including KDoc) with space after the first symbol (`//`, `/*`, `/**` and `*`) **Valid example:** + ```kotlin val x = 0 // this is a comment ``` -### Rule 2.4.2: Do not comment on unused code blocks +#### 2.4.2 Do not comment on unused code blocks + Do not comment on unused code blocks, including imports. Delete these code blocks immediately. A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose. Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained. @@ -298,15 +316,17 @@ In an attempt to reuse the code, there is a high probability that you will intro The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. +#### 2.4.3 Code delivered to the client should not contain TODO/FIXME comments + The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. -They should all have a unified style to facilitate the unified text search processing. +They should all have a unified style to facilitate unified text search processing. + +**Example:** -**Example**: ```kotlin // TODO(): Jira-XXX - support new json format // FIXME: Jira-XXX - fix NPE in this code block ``` -At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released. +At a version development stage, these annotations can be used to highlight the issues in the code, but all of them should be fixed before a new product version is released. \ No newline at end of file diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 10e6dcd026..aca397378d 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -1,13 +1,14 @@ # 3. General formatting (typesetting) ### 3.1 File-related rules -### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines). +This section describes the rules related to using files in your code. +#### 3.1.1 Avoid files that are too long -If the file is too long and complex, it should be split into smaller files, functions, or modules. +If the file is too long and complex, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines). It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. -### Rule 3.1.2: Code blocks in the source file should be separated by one blank line. +#### 3.1.2 Code blocks in the source file should be separated by one blank line A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. a) Code blocks should be in the following order: @@ -26,7 +27,7 @@ d) **Recommendation**. One `.kt` source file should contain only one class decla e) Avoid empty files that do not contain the code or contain only imports/comments/package name -### Recommendation 3.1.3: Import statements order. +#### 3.1.3 Import statements order From top to bottom, the order is the following: 1. Android @@ -56,7 +57,7 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. +#### 3.1.4 Order of declaration parts of class-like code structures The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. Notes: 1. There should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line. @@ -78,7 +79,8 @@ All variants of a `(private) val` logger should be placed in the beginning of th ### 3.2 Braces -### Rule 3.2.1: Braces must be used in conditional statements and loop blocks. +This section describes the general rules of using braces in your code. +#### 3.2.1 Using braces in conditional statements and loop blocks Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements. @@ -118,8 +120,8 @@ if (condition) { } ``` -### Rule 3.2.2 For *non-empty* blocks and block structures, the opening brace is placed at the end of the line - +#### 3.2.2 Opening braces are placed at the end of the line in *non-empty* blocks and block structures +For *non-empty* blocks and block structures, the opening brace is placed at the end of the line. Follow the K&R style (1TBS or OTBS) for *non-empty* code blocks with braces: - The opening brace and first line of the code block are on the same line. - The closing brace is on its own new line. @@ -177,7 +179,6 @@ do { ### 3.3 Indentation -### Rule 3.3.1: Use spaces for indentation. Each indentation equals four spaces. Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted). If you prefer using tabs, simply configure them to change to spaces in your IDE automatically. @@ -252,9 +253,8 @@ class A ### 3.4 Empty blocks -### Recommendation 3.4.1: Avoid empty blocks, and ensure braces start on a new line. -An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.) +Avoid empty blocks, and ensure braces start on a new line. An empty code block can be closed immediately on the same line and the next line. However, a newline is recommended between opening and closing braces `{}` (see the examples below.) Generally, empty code blocks are prohibited; using them is considered a bad practice (especially for catch block). They are only appropriate for overridden functions when the base class's functionality is not needed in the class-inheritor. @@ -289,10 +289,9 @@ try { ### 3.5 Line length -### Recommendation 3.5.1: Line length should be less than 120 symbols. -The international code style prohibits `non-Latin` (`non-ASCII`) symbols. -(See [Rule 1.1.1: Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: +Line length should be less than 120 symbols. The international code style prohibits `non-Latin` (`non-ASCII`) symbols. +(See [Identifiers](#r1.1.1)) However, if you still intend on using them, follow the following convention: - One wide character occupies the width of two narrow characters. The "wide" and "narrow" parts of a character are defined by its [east Asian width Unicode attribute](https://unicode.org/reports/tr11/). @@ -311,7 +310,8 @@ Each one of these characters represents two narrow characters. ### 3.6 Line breaks (newlines) -### Recommendation 3.6.1: Each line can have a maximum of one statement. +This section contains the rules and recommendations on using line breaks. +#### 3.6.1 Each line can have a maximum of one statement. Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** @@ -325,7 +325,7 @@ val a = "" val b = "" ``` -### Rule 3.6.2: Rules for line-breaking +#### 3.6.2 Rules for line-breaking 1) Unlike Java, Kotlin allows you not to put a semicolon (`;`) after each statement separated by a newline character. There should be no redundant semicolon at the end of the lines. @@ -451,10 +451,9 @@ class MyFavouriteVeryLongClassHolder : ``` -### 3.7 Blank lines -### Recommendation 3.7.1: Reduce unnecessary blank lines and maintain a compact code size +### 3.7 Using blank lines -By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. +Reduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. - Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). - Do not use more than one line inside methods, type definitions, and initialization expressions. - Generally, do not use more than two consecutive blank lines in a row. @@ -472,11 +471,14 @@ fun baz() { ### 3.8 Horizontal space -### Rule 3.8.1: Usage of whitespace for code separation +This section describes general rules and recommendations for using spaces in the code. +#### Rule 3.8.1: Separate keywords like `if`, `when`, `for`, e.t.c. from the opening parenthesis with single whitespace. + +Follow the rules below for using space to separate keywords: -**Note:** This recommendation is for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space (described in another rule.) +**Note:** This recommendations are for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. -1. Separate keywords like `if`, `when`, `for`, e.t.c. from the opening parenthesis with single whitespace. +1. Separate keywords (such as `if`, `when`, `for`) from the opening parenthesis with single whitespace. The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis. 2. Separate keywords like `else` or `try` from the opening brace (`{`) with a single whitespace. @@ -506,7 +508,7 @@ fun baz() { `1..100` 5. Use spaces after (`,`), (`:`), and (`;`), except when the symbol is at the end of the line. - However, note that this code style prohibits the use of (`;`) in the middle of a line ([Rule 3.2.2](#r3.2.2)). + However, note that this code style prohibits the use of (`;`) in the middle of a line ([see 3.3.2](#r3.2.2)). There should be no whitespaces at the end of a line. The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`). There should be no spaces before `,` , `:` and `;`. @@ -532,7 +534,7 @@ If the type is nullable, there should be no space before `?`. 7. When using `[]` operator (`get/set`) there should be **no** spaces between identifier and `[` : `someList[0]`. 8. There should be no space between a method or constructor name (both at declaration and at call site) and a parenthesis: - `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [Rule 3.6.2](#r3.6.2). + `foo() {}`. Note that this sub-rule is related only to spaces; the rules for whitespaces are described in [see 3.6.2](#r3.6.2). This rule does not prohibit, for example, the following code: ```kotlin fun foo @@ -545,7 +547,7 @@ fun foo 10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand. -### Recommendation 3.8.2: No spaces should be inserted for horizontal alignment. +#### 3.8.2: No spaces for horizontal alignment *Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because: @@ -577,8 +579,9 @@ enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean ### 3.9 Enumerations -### Recommendation 3.9.1: Enum values are separated by a comma and line break, with ';' placed on the new line. -1) Enum values are separated by a comma and a line break. `;` is put on the new line: +Enum values are separated by a comma and line break, with ';' placed on the new line. + +1) The comma and line break characters separate enum values. Put `;` on the new line: ```kotlin enum class Warnings { A, @@ -623,7 +626,8 @@ enum class ComparisonResult { ### 3.10 Variable declaration -### Rule 3.10.1: Declare one variable per line. +This section describes rules for the declaration of variables. +#### 3.10.1 Declare one variable per line. Each property or variable must be declared on a separate line. @@ -632,23 +636,24 @@ Each property or variable must be declared on a separate line. val n1: Int; val n2: Int ``` -### Recommendation 3.10.2: Variables should be declared near the line where they are first used. +#### 3.10.2 Variables should be declared near the line where they are first used. Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. Local variables are usually initialized during their declaration or immediately after. The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure). -### 3.11 When expression -### Rule 3.11.1: The 'when' statement must have an 'else' branch unless the condition variable is enumerated or a sealed type. +### 3.11 'When' expression + +The `when` statement must have an 'else' branch unless the condition variable is enumerated or a sealed type. Each `when` statement should contain an `else` statement group, even if it does not contain any code. **Exception:** If 'when' statement of the `enum or sealed` type contains all enum values, there is no need to have an "else" branch. The compiler can issue a warning when it is missing. -### 3.12 Annotations -### Recommendation 3.12.1: Each annotation applied to a class, method, or constructor should be placed on its own line. +### 3.12 Using annotations +Each annotation applied to a class, method, or constructor should be placed on its own line. Consider the following examples: 1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). **Valid example**: @@ -673,8 +678,7 @@ fun getNameIfPresent() { /* ... */ } ``` -### 3.13 Layout of comments -### Recommendation 3.13.1: Block comments location. +### 3.13 Block comments Block comments should be placed at the same indentation level as the surrounding code. See examples below. @@ -690,11 +694,13 @@ class SomeClass { } ``` -**Suggestion**: Use `/*...*/` block comments to enable automatic formatting by IDEs. +**Note**: Use `/*...*/` block comments to enable automatic formatting by IDEs. ### 3.14 Modifiers and constant values -### Recommendation 3.14.1: If a declaration has multiple modifiers, always follow the proper sequence. +This section contains recommendations regarding modifiers and constant values. +#### 3.14.1 Declaration with multiple modifiers +If a declaration has multiple modifiers, always follow the proper sequence. **Valid sequence:** ```kotlin @@ -719,7 +725,8 @@ operator data ``` -### Recommendation 3.14.2: An underscore should separate long numerical values. +#### 3.14.2: Separate long numerical values with an underscore +An underscore character should separate long numerical values. **Note:** Using underscores simplifies reading and helps to find errors in numeric constants. ```kotlin val oneMillion = 1_000_000 @@ -731,7 +738,9 @@ val bytes = 0b11010010_01101001_10010100_10010010 ### 3.15 Strings -### Rule 3.15.1: Concatenation of Strings is prohibited if the string can fit on one line. +This section describes the general rules of using strings. + +#### 3.15.1 Concatenation of Strings String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: [String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline charcters. @@ -748,7 +757,7 @@ val myStr = "Super string" val value = "$myStr concatenated" ``` -### Rule 3.15.2: String template format +#### 3.15.2 String template format **Redundant curly braces in string templates** If there is only one variable in a string template, there is no need to use such a template. Use this variable directly. diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index 5485ceab75..5f4d88a81a 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -1,7 +1,9 @@ # 4. Variables and types +This section is dedicated to the rules and recommendations for using variables and types in your code. ### 4.1 Variables -### Rule 4.1.1: Do not use Float and Double types when accurate calculations are needed. +The rules of using variables are explained in the below topics. +#### 4.1.1 Do not use Float and Double types when accurate calculations are needed Floating-point numbers provide a good approximation over a wide range of values, but they cannot produce accurate results in some cases. Binary floating-point numbers are unsuitable for precise calculations because it is impossible to represent 0.1 or any other negative power of 10 in a `binary representation` with a finite length. @@ -29,8 +31,8 @@ Float values containing more than six or seven decimal numbers will be rounded. println(income.subtract(expense)) // you will obtain 0.9 here ``` -### Rule 4.1.2: Numeric float type values should not be directly compared with the equality operator (==) or other methods like `compareTo()` and `equals()`. -Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems. +#### 4.1.2: Comparing numeric float type values +Numeric float type values should not be directly compared with the equality operator (==) or other methods, such as `compareTo()` and `equals()`. Since floating-point numbers involve precision problems in computer representation, it is better to use `BigDecimal` as recommended in [Rule 4.1.1](#r4.1.1) to make accurate computations and comparisons. The following code describes these problems. **Invalid example**: ```kotlin @@ -63,16 +65,17 @@ if (abs(foo - bar) > 1e-6f) { } ``` -### Rule 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]. +#### 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]. Variables with the `val` modifier are immutable (read-only). -Code robustness and readability increase when using `val` variables instead of `var` variables. +Using `val` variables instead of `var` variables increases code robustness and readability. This is because `var` variables can be reassigned several times in the business logic. However, in some scenarios with loops or accumulators, only `var`s are permitted. ### 4.2 Types -### Recommendation 4.2.1: Use Contracts and smart cast as much as possible. +This section provides recommendations for using types. +#### 4.2.1: Use Contracts and smart cast as much as possible. The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code. @@ -120,7 +123,7 @@ fun foo(s: String?) { } ``` -### Recommendation 4.2.2: Try to use type alias to represent types making code more readable. +#### 4.2.2: Try to use type alias to represent types making code more readable. Type aliases provide alternative names for existing types. If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. @@ -149,7 +152,7 @@ typealias Predicate = (T) -> Boolean ### 4.3 Null safety and variable declarations Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. -### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. +#### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: @@ -176,7 +179,7 @@ val a: List? = null val a: List = emptyList() ``` -### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. +#### Recommendation 4.3.2: Variables of generic types should have an explicit type declaration. Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: ```kotlin diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md index 6ed8f268a4..8913f7f7f1 100644 --- a/info/guide/guide-chapter-5.md +++ b/info/guide/guide-chapter-5.md @@ -1,18 +1,19 @@ # 5. Functions +This section describes the rules of using functions in your code. ### 5.1 Function design Developers can write clean code by gaining knowledge of how to build design patterns and avoid code smells. You should utilize this approach, along with functional style, when writing Kotlin code. The concepts behind functional style are as follows: Functions are the smallest unit of combinable and reusable code. -They should have clean logic, **high cohesion**, and **low coupling** to effectively organize the code. +They should have clean logic, **high cohesion**, and **low coupling** to organize the code effectively. The code in functions should be simple and not conceal the author's original intentions. Additionally, it should have a clean abstraction, and control statements should be used straightforwardly. The side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object. The only exceptions to this are state machines. Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. -Also, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments (???). +Also, it supports standard collections, and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input. The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics: 1. Simplicity @@ -25,7 +26,7 @@ The pipeline data flow for the pure function comprises a functional paradigm. It There can be only one side effect in this data stream, which can be placed only at the end of the execution queue. -### Rule 5.1.1: Avoid functions that are too long. +#### 5.1.1 Avoid functions that are too long The function should be displayable on one screen and only implement one certain logic. If a function is too long, it often means complex and could be split or simplified. Functions should consist of 30 lines (non-empty and non-comment) in total. @@ -36,7 +37,7 @@ Linter warnings for such functions **can be suppressed**. Even if a long function works well, new problems or bugs may appear due to the function's complex logic once it is modified by someone else. Therefore, it is recommended to split such functions into several separate and shorter functions that are easier to manage. This approach will enable other programmers to read and modify the code properly. -### Rule 5.1.2: Avoid deep nesting of function code blocks, limiting to four levels. +#### 5.1.2 Avoid deep nesting of function code blocks, limiting to four levels The nesting depth of a function's code block is the depth of mutual inclusion between the code control blocks in the function (for example: if, for, while, and when). Each nesting level will increase the amount of effort needed to read the code because you need to remember the current "stack" (for example, entering conditional statements and loops). @@ -44,7 +45,7 @@ Each nesting level will increase the amount of effort needed to read the code be Functional decomposition should be implemented to avoid confusion for the developer who reads the code. This will help the reader switch between contexts. -### Rule 5.1.3: Avoid using nested functions. +#### Rule 5.1.3 Avoid using nested functions Nested functions create a more complex function context, thereby confusing readers. With nested functions, the visibility context may not be evident to the code reader. @@ -60,7 +61,8 @@ fun foo() { ### 5.2 Function arguments -### Rule 5.2.1: The lambda parameter of the function should be placed at the end of the argument list. +The rules for using function arguments are described in the below topics. +#### 5.2.1 The lambda parameter of the function should be placed at the end of the argument list With such notation, it is easier to use curly brackets, leading to better code readability. @@ -77,14 +79,14 @@ println("hey") } ``` -### Rule 5.2.2: Number of function parameters should be limited to 5 +#### 5.2.2 Number of function parameters should be limited to five A long argument list is a [code smell](https://en.wikipedia.org/wiki/Code_smell) that leads to less reliable code. It is recommended to reduce the number of parameters. Having **more than five** parameters leads to difficulties in maintenance and conflicts merging. If parameter groups appear in different functions multiple times, these parameters are closely related and can be encapsulated into a single Data Class. It is recommended that you use Data Classes and Maps to unify these function arguments. -### Rule 5.2.3 Use default values for function arguments instead of overloading them +#### 5.2.3 Use default values for function arguments instead of overloading them In Java, default values for function arguments are prohibited. That is why the function should be overloaded when you need to create a function with fewer arguments. In Kotlin, you can use default arguments instead. diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index 4760a7e0f5..40d1c2e858 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -1,8 +1,9 @@ -# 6. Classes, interfaces and extension functions +# 6. Classes, interfaces, and extension functions ### 6.1 Classes -### Rule 6.1.1: When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. -In case the class contains only one explicit constructor - it should be converted to a primary constructor. +This section describes the rules of denoting classes in your code. +#### 6.1.1 Denoting a class with a single constructor +When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. In case the class contains only one explicit constructor - it should be converted to a primary constructor. **Invalid example**: ```kotlin @@ -26,7 +27,7 @@ class Test private constructor(var a: Int) { } ``` -### Rule 6.1.2: Prefer data classes instead of classes without any functional logic. +#### 6.1.2 Prefer data classes instead of classes without any functional logic Some people say that the data class is a code smell. However, if you need to use it (which makes your code more simple), you can utilize the Kotlin `data class`. The main purpose of this class is to hold data, but also `data class` will automatically generate several useful methods: - equals()/hashCode() pair; @@ -72,7 +73,7 @@ data class Test1(var a: Int = 0, var b: Int = 0) **Exception 2**: No need to convert a class to a data class if this class extends some other class or implements an interface. -### Rule 6.1.3: Do not use the primary constructor if it is empty or useless. +#### 6.1.3 Do not use the primary constructor if it is empty or useless The primary constructor is a part of the class header; it is placed after the class name and type parameters (optional) but can be omitted if it is not used. **Invalid example**: @@ -107,12 +108,12 @@ class Test { } ``` -### Rule 6.1.4: several init blocks are redundant and generally should not be used in your class. -The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks. +#### 6.1.4 Do not use redundant init blocks in your class +Several init blocks are redundant and generally should not be used in your class. The primary constructor cannot contain any code. That is why Kotlin has introduced `init` blocks. These blocks store the code to be run during the class initialization. Kotlin allows writing multiple initialization blocks executed in the same order as they appear in the class body. Even when you follow (rule 3.2)[#r3.2], this makes your code less readable as the programmer needs to keep in mind all init blocks and trace the execution of the code. -Therefore, you should try to use a single `init` block to reduce the code's complexity. . If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and +Therefore, you should try to use a single `init` block to reduce the code's complexity. If you need to do some logging or make some calculations before the class property assignment, you can use powerful functional programming. This will reduce the possibility of the error if your `init` blocks' order is accidentally changed and make the code logic more coupled. It is always enough to use one `init` block to implement your idea in Kotlin. **Invalid example**: @@ -165,8 +166,8 @@ class A(baseUrl: String) { } ``` -### Rule 6.1.5: Explicit supertype qualification should not be used if there is not clash between called methods. -This rule is applicable to both interfaces and classes. +#### 6.1.5 Explicit supertype qualification +The explicit supertype qualification should not be used if there is no clash between called methods. This rule is applicable to both interfaces and classes. **Invalid example**: ```kotlin @@ -181,7 +182,7 @@ class Square() : Rectangle() { } ``` -### Rule 6.1.6: Abstract class should have at least one abstract method. +#### 6.1.6 Abstract class should have at least one abstract method Abstract classes are used to force a developer to implement some of its parts in their inheritors. When the abstract class has no abstract methods, it was set `abstract` incorrectly and can be converted to a regular class. @@ -211,7 +212,7 @@ class NotAbstract { ``` -### Rule 6.1.7: in case of using "implicit backing property" scheme, the name of real and back property should be the same. +#### 6.1.7 When using the "implicit backing property" scheme, the name of real and back property should be the same Kotlin has a mechanism of [backing properties](https://kotlinlang.org/docs/reference/properties.html#backing-properties). In some cases, implicit backing is not enough and it should be done explicitly: ```kotlin @@ -228,7 +229,7 @@ val table: Map In this case, the name of the backing property (`_table`) should be the same as the name of the real property (`table`) but should have an underscore (`_`) prefix. It is one of the exceptions from the [identifier names rule](#r1.2) -### Recommendation 6.1.8: avoid using custom getters and setters. +#### 6.1.8 Avoid using custom getters and setters Kotlin has a perfect mechanism of [properties](https://kotlinlang.org/docs/reference/properties.html#properties-and-fields). Kotlin compiler automatically generates `get` and `set` methods for properties and can override them. @@ -245,9 +246,9 @@ class A { } ``` -From the callee code these methods look like an access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter. +From the callee code, these methods look like access to this property: `A().isEmpty = true` for setter and `A().isEmpty` for getter. -However, when `get` and `set` are overridden, it is very confusing for a developer who uses this particular class. +However, when `get` and `set` are overridden, it isn't very clear for a developer who uses this particular class. The developer expects to get the property value but receives some unknown value and some extra side-effect hidden by the custom getter/setter. Use extra functions instead to avoid confusion. @@ -268,7 +269,7 @@ class A { **Exception:** `Private setters` are only exceptions that are not prohibited by this rule. -### Rule 6.1.9: never use the name of a variable in the custom getter or setter (possible_bug). +#### 6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug) If you ignored [recommendation 6.1.8](#r6.1.8), be careful with using the name of the property in your custom getter/setter as it can accidentally cause a recursive call and a `StackOverflow Error`. Use the `field` keyword instead. @@ -282,7 +283,7 @@ var isEmpty: Boolean get() = isEmpty ``` -### Recommendation 6.1.10 no trivial getters and setters are allowed in the code. +#### 6.1.10 No trivial getters and setters are allowed in the code In Java, trivial getters - are the getters that are just returning the field value. Trivial setters - are merely setting the field with a value without any transformation. However, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin. @@ -309,7 +310,7 @@ class A { } ``` -### Rule 6.1.11: use apply for grouping object initialization. +#### Use 'apply' for grouping object initialization In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -358,18 +359,19 @@ fun main() { ### 6.2 Extension functions +This section describes the rules of using extension functions in your code. + [Extension functions](https://kotlinlang.org/docs/reference/extensions.html) is a killer-feature in Kotlin. -It gives you a chance to extend classes that were already implemented in external libraries and help you to make classes less heavy. +It gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy. Extension functions are resolved statically. -### Recommendation 6.2.1: use extension functions for making logic of classes less coupled. +#### 6.2.1 Use extension functions for making logic of classes less coupled It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer. -### Rule 6.2.2: No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug). -As extension functions are resolved statically. In this case, there could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. +#### 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug) +You should have ho extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).esolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. This can lead to an issue when an incorrect method is used. -And that can lead to an issue when incorrect method is used. **Invalid example**: ```kotlin @@ -397,8 +399,9 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects -### Rule 6.4.1: Avoid using utility classes/objects, use extensions instead. -As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. +This section describes the rules of using objects in code. +#### 6.4.1 Instead of using utility classes/objects, use extensions. +Avoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. **Invalid example**: @@ -420,7 +423,7 @@ fun String.stringInfo(): Int { "myStr".stringInfo() ``` -### Recommendation 6.4.2: Objects should be used for Stateless Interfaces. +#### 6.4.2 Objects should be used for Stateless Interfaces. Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. diff --git a/info/guide/guide-chapter-8.md b/info/guide/guide-chapter-8.md index 76b3d9c9f2..0cac289bc9 100644 --- a/info/guide/guide-chapter-8.md +++ b/info/guide/guide-chapter-8.md @@ -1,7 +1,7 @@ -# 8. Things that will be moved to a main guide later +# 8. Things that will be moved to the main guide later ### Null-safety -### 4.3.3 Explicit null checks +#### 4.3.3 Explicit null checks Try to avoid explicit null checks (explicit comparison with `null`) Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. From 9b56173d058845431e0d73a7865a342f59c0b53b Mon Sep 17 00:00:00 2001 From: vtchem Date: Mon, 7 Dec 2020 23:16:44 +0300 Subject: [PATCH 12/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-chapter-1.md | 12 +++++----- info/guide/guide-chapter-2.md | 12 +++++----- info/guide/guide-chapter-3.md | 41 ++++++++++++++++++----------------- info/guide/guide-chapter-5.md | 5 +++-- info/guide/guide-chapter-6.md | 4 ++-- 5 files changed, 38 insertions(+), 36 deletions(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 619603a487..551c4c2e28 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -86,7 +86,7 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces -This section describes the general rules for naming classes, enumerations, and interfaces +This section describes the general rules for naming classes, enumerations, and interfaces. ### 1.3.1 Classes, enumerations, interface names use Camel case Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below: 1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. @@ -161,14 +161,14 @@ fun draw() fun addKeyListener(Listener) ``` -2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. +2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. ### 1.5 Constants This section describes the general rules for naming constraints. ### 1.5.1 Using UPPER case and underscore characters in a constraint name -Constant names should be in UPPER case, words separated by underscore. The jeneral constant naming conventions are listed below: -1. Constants are attributes created with the `const` keyword, or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain a fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. -2. Constant names should contain only uppercase letters separated by underscores. They should have a val or const val modifier to to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. +Constant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below: +1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. +2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. 3. Objects with immutable content, such as `Logger` and `Lock`, can be in uppercase as constants or have camel case as regular variables. 4. Use meaningful constants instead of `magic numbers`. SQL or logging strings should not be treated as magic numbers, nor should they be defined as string constants. Magic constants, such as `NUM_FIVE = 5` or `NUM_5 = 5` should not be treated as constants. This is because mistakes will easily be made if they are changed to `NUM_5 = 50` or 55. @@ -216,7 +216,7 @@ val mutableCollection: MutableSet = HashSet() ### 1.6.2 Boolean variable names with negative meaning -Avoid using Boolean variable names with a negative meaning. When using a logical operator and name with negative meaning, the code may be difficult to understand, which is referred to as the "double negative". +Avoid using Boolean variable names with a negative meaning. When using a logical operator and name with a negative meaning, the code may be difficult to understand, which is referred to as the "double negative". For instance, it is not easy to understand the meaning of !isNotError. The JavaBeans specification automatically generates isXxx() getters for attributes of Boolean classes. However, not all methods returning Boolean type have this notation. diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 780bc97e9f..46128dfe96 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -68,7 +68,7 @@ class Example( **Exceptions:** -* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note, that Kotlin generates simple `get/set` methods under the hood. +* For setters/getters of properties, obvious comments (like `this getter returns field`) are optional. Note that Kotlin generates simple `get/set` methods under the hood. * It is optional to add comments for simple one-line methods, such as shown in the example below: ```kotlin @@ -99,7 +99,7 @@ When the method has such details as arguments, return value, or can throw except protected abstract class Sample { /** * This is a long comment with whitespace that should be split in - * comments on multiple lines in case the line comment formatting is enabled. + * comments on multiple lines if the line comment formatting is enabled. * / * Add a blank line between the comment text and each KDoc tag underneath * / * @param fox A quick brown fox jumps over the lazy dog * @return battle between fox and dog @@ -202,7 +202,7 @@ The following example is a copyright statement for Huawei, without other functio The following factors should be considered when writing the file header or comments for top-level classes: - File header comments must start from the top of the file. If it is a top-level file comment, there should be a blank line after the last Kdoc `*/` symbol. If it is a comment for a top-level class, the class declaration should start immediately without using a newline. -- Maintain a unified format. The specific format can be formulated by the project (for example, if you use existing opensource project), and you need to follow it. +- Maintain a unified format. The specific format can be formulated by the project (for example, if you use an existing opensource project), and you need to follow it. - A top-level file-Kdoc must include a copyright and functional description, especially if there is more than one top-level class. - Do not include empty comment blocks. If there is no content after the option `@apiNote`, the entire tag block should be deleted. - The industry practice is not to include historical information in the comments. The corresponding history can be found in VCS (git, svn, etc.). Therefore, it is not recommended to include historical data in the comments of the Kotlin source code. @@ -223,9 +223,9 @@ This section describes the general rules of adding code comments. #### 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: -- There must be one space between the comment character and the content of the comment -- There must be a newline between a Kdoc and the pressiding code -- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular name space (code block) (for example, between the function declaration and first comment in a function body). +- There must be one space between the comment character and the content of the comment. +- There must be a newline between a Kdoc and the presiding code. +- An empty line should not exist between a Kdoc and the code it is describing. You do not need to add a blank line before the first comment in a particular namespace (code block) (for example, between the function declaration and first comment in a function body). **Valid Examples:** diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 6a35972b54..3f3f58476b 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -4,7 +4,7 @@ This section describes the rules related to using files in your code. #### 3.1.1 Avoid files that are too long -If the file is too long and complex, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines). +If the file is too long and complicated, it should be split into smaller files, functions, or modules. Files should not exceed 2000 lines (non-empty and non-commented lines). It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. @@ -71,11 +71,11 @@ The declaration part of a class or interface should be in the following order: - Init-blocks - Constructors - Methods or nested classes. Put nested classes next to the code they are used by. -If the classes are meant to be used externally and are not referenced inside the class, put them after the companion object. +If the classes are meant to be used externally, and are not referenced inside the class, put them after the companion object. - Companion object **Exception:** -All variants of a `(private) val` logger should be placed in the beginning of the class (`(private) val log`, `LOG`, `logger`, etc.). +All variants of a `(private) val` logger should be placed at the beginning of the class (`(private) val log`, `LOG`, `logger`, etc.). ### 3.2 Braces @@ -183,7 +183,7 @@ do { Only spaces are permitted for indentation, and each indentation should equal `four spaces` (tabs are not permitted). If you prefer using tabs, simply configure them to change to spaces in your IDE automatically. These code blocks should be indented if they are placed on the new line, and the following conditions are met: -- The code block is placed immediately after an opening brace +- The code block is placed immediately after an opening brace. - The code block is placed after each operator, including the assignment operator (`+`/`-`/`&&`/`=`/etc.) - The code block is a call chain of methods: ```kotlin @@ -209,7 +209,7 @@ b) Arguments in argument lists can be aligned if they are on different lines. 3. Eight spaces are used for functional-like styles when the newline is placed before the dot. -4. Super type lists: \ +4. Supertype lists: \ a) Four spaces are used if the colon before the supertype list is on a new line. \ b) Four spaces are used before each supertype, and eight spaces are used if the colon is on a new line. @@ -440,7 +440,7 @@ fun foo( } ``` -8) If the supertype list has more than two elements, they should be separated by newlines +8) If the supertype list has more than two elements, they should be separated by newlines. **Valid example:** ```kotlin @@ -454,7 +454,7 @@ class MyFavouriteVeryLongClassHolder : ### 3.7 Using blank lines Reduce unnecessary blank lines and maintain a compact code size. By reducing unnecessary blank lines, you can display more code on one screen, which improves code readability. -- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [Rule 3.1.2](#r3.1.2)). +- Blank lines should separate content based on relevance and should be placed between groups of fields, constructors, methods, nested classes, `init` blocks, and objects (see [3.1.2](#r3.1.2)). - Do not use more than one line inside methods, type definitions, and initialization expressions. - Generally, do not use more than two consecutive blank lines in a row. - Do not put newlines in the beginning or end of code blocks with curly braces. @@ -474,14 +474,14 @@ fun baz() { This section describes general rules and recommendations for using spaces in the code. #### 3.8.1: Usage of whitespace for code separation -Follow the rules below for using space to separate keywords: +Follow the recommendations below for using space to separate keywords: -**Note:** This recommendations are for the cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. +**Note:** These recommendations are for cases where symbols are located on the same line. However, in some cases, a line break could be used instead of a space. 1. Separate keywords (such as `if`, `when`, `for`) from the opening parenthesis with single whitespace. The only exception is the `constructor` keyword, which should not be separated from the opening parenthesis. -2. Separate keywords like `else` or `try` from the opening brace (`{`) with a single whitespace. +2. Separate keywords like `else` or `try` from the opening brace (`{`) with single whitespace. If `else` is used in a ternary-style statement without braces, there should be a single space between `else` and the statement after: `if (condition) foo() else bar()` 3. Use a **single** whitespace before all opening braces (`{`). The only exception is the passing of a lambda as a parameter inside parentheses: @@ -490,7 +490,7 @@ Follow the rules below for using space to separate keywords: foo({x: Int -> x}, 5) // no space before '{' ``` -4. A single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols. +4. Single whitespace should be placed on both sides of binary operators. This also applies to operator-like symbols. For example: - A colon in generic structures with the `where` keyword: `where T : Type` @@ -512,10 +512,11 @@ Follow the rules below for using space to separate keywords: There should be no whitespaces at the end of a line. The only scenario where there should be no space after a colon is when the colon is used in the annotation to specify a use-site target (for example, `@param:JsonProperty`). There should be no spaces before `,` , `:` and `;`. - **Exceptions** for spaces and colons are the following: - - when `:` is used to separate a type and a supertype, including an anonymous object (after object keyword) - - when delegating to a superclass constructor or different constructor of the same class + **Exceptions** for spaces and colons: + + - When `:` is used to separate a type and a supertype, including an anonymous object (after object keyword) + - When delegating to a superclass constructor or different constructor of the same class **Valid example:** ```kotlin @@ -560,7 +561,7 @@ Recommendation: Alignment only looks suitable for `enum class`, where it can be enum class Warnings(private val id: Int, private val canBeAutoCorrected: Boolean, private val warn: String) : Rule { PACKAGE_NAME_MISSING (1, true, "no package name declared in a file"), PACKAGE_NAME_INCORRECT_CASE (2, true, "package name should be completely in a lower case"), - PACKAGE_NAME_INCORRECT_PREFIX(3, false, "package name should start from company's domain") + PACKAGE_NAME_INCORRECT_PREFIX(3, false, "package name should start from the company's domain") ; } ``` @@ -592,7 +593,7 @@ enum class Warnings { ``` This will help to resolve conflicts and reduce the number of conflicts during merging pull requests. -Also use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma). +Also, use [trailing comma](https://kotlinlang.org/docs/reference/whatsnew14.html#trailing-comma). 2) If the enum is simple (no properties, methods, and comments inside), you can declare it in a single line: ```kotlin @@ -653,8 +654,8 @@ The compiler can issue a warning when it is missing. ### 3.12 Annotations -Each annotation applied to a class, method, or constructor should be placed on its own line. Consider the following examples: -1. Annotations applied to the class, method, or constructor are placed on separate lines (one annotation per line). +Each annotation applied to a class, method or constructor should be placed on its own line. Consider the following examples: +1. Annotations applied to the class, method or constructor are placed on separate lines (one annotation per line). **Valid example**: ```kotlin @@ -742,8 +743,8 @@ This section describes the general rules of using strings. #### 3.15.1 Concatenation of Strings String concatenation is prohibited if the string can fit on one line. Use raw strings and string templates instead. Kotlin has significantly improved the use of Strings: -[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals) -Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline charcters. +[String templates](https://kotlinlang.org/docs/reference/basic-types.html#string-templates), [Raw strings](https://kotlinlang.org/docs/reference/basic-types.html#string-literals). +Therefore, compared to using explicit concatenation, code looks much better when proper Kotlin strings are used for short lines, and you do not need to split them with newline characters. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-5.md b/info/guide/guide-chapter-5.md index 98efc303b1..90484651a3 100644 --- a/info/guide/guide-chapter-5.md +++ b/info/guide/guide-chapter-5.md @@ -8,12 +8,13 @@ The concepts behind functional style are as follows: Functions are the smallest unit of combinable and reusable code. They should have clean logic, **high cohesion**, and **low coupling** to organize the code effectively. The code in functions should be simple and not conceal the author's original intentions. + Additionally, it should have a clean abstraction, and control statements should be used straightforwardly. The side effects (code that does not affect a function's return value but affects global/object instance variables) should not be used for state changes of an object. The only exceptions to this are state machines. Kotlin is [designed](https://www.slideshare.net/abreslav/whos-more-functional-kotlin-groovy-scala-or-java) to support and encourage functional programming, featuring the corresponding built-in mechanisms. -Also, it supports standard collections, and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. +Also, it supports standard collections and sequences feature methods that enable functional programming (for example, `apply`, `with`, `let`, and `run`), Kotlin Higher-Order functions, function types, lambdas, and default function arguments. As [previously discussed](#r4.1.3), Kotlin supports and encourages the use of immutable types, which in turn motivates programmers to write pure functions that avoid side effects and have a corresponding output for specific input. The pipeline data flow for the pure function comprises a functional paradigm. It is easy to implement concurrent programming when you have chains of function calls, where each step features the following characteristics: 1. Simplicity @@ -47,7 +48,7 @@ This will help the reader switch between contexts. #### Rule 5.1.3 Avoid using nested functions Nested functions create a more complex function context, thereby confusing readers. -With nested functions the visibility context may not be evident to the code reader. +With nested functions, the visibility context may not be evident to the code reader. **Invalid example**: ```kotlin diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index 40d1c2e858..af1bc28829 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -3,7 +3,7 @@ ### 6.1 Classes This section describes the rules of denoting classes in your code. #### 6.1.1 Denoting a class with a single constructor -When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. In case the class contains only one explicit constructor - it should be converted to a primary constructor. +When a class has a single constructor, it should be defined as a primary constructor in the declaration of the class. If the class contains only one explicit constructor, it should be converted to a primary constructor. **Invalid example**: ```kotlin @@ -401,7 +401,7 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects This section describes the rules of using objects in code. #### 6.4.1 Instead of using utility classes/objects, use extensions. -Avoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), extension functions are a powerful. Instead of using utility classes/objects, use it extention functions. +Avoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method. This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. **Invalid example**: From d00876a899e43b4897d439ab28ed71c9855fba14 Mon Sep 17 00:00:00 2001 From: vtchem Date: Tue, 8 Dec 2020 23:10:09 +0300 Subject: [PATCH 13/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-chapter-1.md | 2 +- info/guide/guide-chapter-2.md | 2 +- info/guide/guide-chapter-3.md | 16 ++++++++-------- info/guide/guide-chapter-4.md | 10 +++++----- info/guide/guide-chapter-6.md | 12 ++++++------ 5 files changed, 21 insertions(+), 21 deletions(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index a6de873c0a..cb5ababec5 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -6,7 +6,7 @@ Note: The source file encoding format (including comments) must be UTF-8 only. T ### 1.1 Identifier names This section describes the general rules for naming identifiers. -### 1.1.1 Identifiers naming conventions +#### 1.1.1 Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. diff --git a/info/guide/guide-chapter-2.md b/info/guide/guide-chapter-2.md index 46128dfe96..afe3550248 100644 --- a/info/guide/guide-chapter-2.md +++ b/info/guide/guide-chapter-2.md @@ -314,7 +314,7 @@ In an attempt to reuse the code, there is a high probability that you will intro The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -#### 2.4.3 Code delivered to the client should not contain TODO/FIXME comments +#### 2.4.3 Code delivered to the client should not contain TODO/FIXME comments The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 3f3f58476b..183944f5b6 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -27,7 +27,7 @@ d) **Recommendation**: One `.kt` source file should contain only one class decla e) Avoid empty files that do not contain the code or contain only imports/comments/package name -#### 3.1.3 Import statements order +#### 3.1.3 Import statements order From top to bottom, the order is the following: 1. Android @@ -57,7 +57,7 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -#### 3.1.4 Order of declaration parts of class-like code structures +#### 3.1.4 Order of declaration parts of class-like code structures The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. Notes: 1. There should be no blank lines between properties with the following **exceptions**: when there is a comment before a property on a separate line or annotations on a separate line. @@ -311,7 +311,7 @@ Each one of these characters represents two narrow characters. ### 3.6 Line breaks (newlines) This section contains the rules and recommendations on using line breaks. -#### 3.6.1 Each line can have a maximum of one statement. +#### 3.6.1 Each line can have a maximum of one statement. Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** @@ -472,7 +472,7 @@ fun baz() { ### 3.8 Horizontal space This section describes general rules and recommendations for using spaces in the code. -#### 3.8.1: Usage of whitespace for code separation +#### 3.8.1: Usage of whitespace for code separation Follow the recommendations below for using space to separate keywords: @@ -548,7 +548,7 @@ fun foo 10. There should be no spaces between a prefix/postfix operator (like `!!` or `++`) and its operand. -#### 3.8.2: No spaces for horizontal alignment +#### 3.8.2: No spaces for horizontal alignment *Horizontal alignment* refers to aligning code blocks by adding space to the code. Horizontal alignment should not be used because: @@ -637,7 +637,7 @@ Each property or variable must be declared on a separate line. val n1: Int; val n2: Int ``` -#### 3.10.2 Variables should be declared near the line where they are first used. +#### 3.10.2 Variables should be declared near the line where they are first used. Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. Local variables are usually initialized during their declaration or immediately after. The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure). @@ -700,7 +700,7 @@ class SomeClass { ### 3.14 Modifiers and constant values This section contains recommendations regarding modifiers and constant values. -#### 3.14.1 Declaration with multiple modifiers +#### 3.14.1 Declaration with multiple modifiers If a declaration has multiple modifiers, always follow the proper sequence. **Valid sequence:** @@ -726,7 +726,7 @@ operator data ``` -#### 3.14.2: Separate long numerical values with an underscore +#### 3.14.2: Separate long numerical values with an underscore An underscore character should separate long numerical values. **Note:** Using underscores simplifies reading and helps to find errors in numeric constants. ```kotlin diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index 67d3238708..f6ebc67a23 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -75,7 +75,7 @@ However, in some scenarios with loops or accumulators, only `var`s are permitted ### 4.2 Types This section provides recommendations for using types. -#### 4.2.1: Use Contracts and smart cast as much as possible. +#### 4.2.1: Use Contracts and smart cast as much as possible. The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code. @@ -123,7 +123,7 @@ fun foo(s: String?) { } ``` -#### 4.2.2: Try to use type alias to represent types making code more readable. +#### 4.2.2: Try to use type alias to represent types making code more readable. Type aliases provide alternative names for existing types. If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. @@ -152,7 +152,7 @@ typealias Predicate = (T) -> Boolean ### 4.3 Null safety and variable declarations Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. -#### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. +#### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: @@ -179,7 +179,7 @@ val a: List? = null val a: List = emptyList() ``` -#### 4.3.2: Variables of generic types should have an explicit type declaration +#### 4.3.2: Variables of generic types should have an explicit type declaration Like in Java, classes in Kotlin may have type parameters. To create an instance of such a class, we typically need to provide type arguments: ```kotlin @@ -199,7 +199,7 @@ val myVariable = emptyMap() val myVariable: Map = emptyMap() ``` -#### Null-safety +#### Null-safety Try to avoid explicit null checks (explicit comparison with `null`) Kotlin is declared as [Null-safe](https://kotlinlang.org/docs/reference/null-safety.html) language. diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index af1bc28829..dbb410c7e6 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -283,7 +283,7 @@ var isEmpty: Boolean get() = isEmpty ``` -#### 6.1.10 No trivial getters and setters are allowed in the code +#### 6.1.10 No trivial getters and setters are allowed in the code In Java, trivial getters - are the getters that are just returning the field value. Trivial setters - are merely setting the field with a value without any transformation. However, in Kotlin, trivial getters/setters are generated by default. There is no need to use it explicitly for all types of data structures in Kotlin. @@ -310,7 +310,7 @@ class A { } ``` -#### Use 'apply' for grouping object initialization +#### Use 'apply' for grouping object initialization In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -365,11 +365,11 @@ This section describes the rules of using extension functions in your code. It gives you a chance to extend classes that were already implemented in external libraries and helps you to make classes less heavy. Extension functions are resolved statically. -#### 6.2.1 Use extension functions for making logic of classes less coupled +#### 6.2.1 Use extension functions for making logic of classes less coupled It is recommended that for classes, the non-tightly coupled functions, which are rarely used in the class, should be implemented as extension functions where possible. They should be implemented in the same class/file where they are used. This is a non-deterministic rule, so the code cannot be checked or fixed automatically by a static analyzer. -#### 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug) +#### 6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug) You should have ho extension functions with the same name and signature if they extend base and inheritor classes (possible_bug).esolved statically. There could be a situation when a developer implements two extension functions: one is for the base class and another for the inheritor. This can lead to an issue when an incorrect method is used. @@ -400,7 +400,7 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects This section describes the rules of using objects in code. -#### 6.4.1 Instead of using utility classes/objects, use extensions. +#### 6.4.1 Instead of using utility classes/objects, use extensions. Avoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method. This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. @@ -423,7 +423,7 @@ fun String.stringInfo(): Int { "myStr".stringInfo() ``` -#### 6.4.2 Objects should be used for Stateless Interfaces. +#### 6.4.2 Objects should be used for Stateless Interfaces. Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. From c9514882c9bbbecdb92e4a3400871aedf89741cf Mon Sep 17 00:00:00 2001 From: vtchem Date: Fri, 18 Dec 2020 15:49:54 +0300 Subject: [PATCH 14/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/guide-TOC.md | 107 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 107 insertions(+) create mode 100644 info/guide/guide-TOC.md diff --git a/info/guide/guide-TOC.md b/info/guide/guide-TOC.md new file mode 100644 index 0000000000..82402abbcb --- /dev/null +++ b/info/guide/guide-TOC.md @@ -0,0 +1,107 @@ + +# Table of contents +I [Preface](#c0) +* [I.I Purpose of this document](#c0.1) +* [I.II General principles](#c0.2) +* [I.III Terminology](#c0.3) +* [I.IV Exceptions](#c0.4) + +[1. Naming](#c1) + +* [1.1 Identifiers](#c1.1) +* [1.2 Packages](#c1.2) +* [1.3 Classes, enumerations, interfaces](#c1.3) +* [1.4 Functions](#c1.4) +* [1.5 Constants](#c1.5) +* [1.6 Non-constant fields (variables)](#c1.6) + * [1.6.1 Non-constant field name](#r1.6.1) + * [1.6.2 Boolean variable names with negative meaning](#r1.6.2) + +[2. Comments](#c2) +* [2.1 General form of Kdoc](#c2.1) + * [Using KDoc for the public, protected, or internal code elements](#r2.1.1) + * [Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2) + * [Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3) +* [2.2 Adding comments on the file header](#c2.2) +* [2.3 Comments on the function header](#c2.3) +* [2.4 Code comments](#c2.4) + * [2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks](#r2.4.1) + * [2.4.2 Do not comment on unused code blocks](#r2.4.2) + * [2.4.3 Do not comment on unused code blocks](#r2.4.3) + +[3. General formatting (typesetting)](#c3) +* [3.1 File-related rules](#c3.1) + * [3.1.1 Avoid files that are too long](#r3.1.1) + * [3.1.2 Code blocks in the source file should be separated by one blank line](#r3.1.2) + * [3.1.3 Import statements order](#r3.1.3) + * [3.1.4 Order of declaration parts of class-like code structures](#r3.1.4) +* [3.2 Braces](#c3.2) + * [3.2.1 Using braces in conditional statements and loop blocks](#r3.2.1) + * [3.2.2 Opening braces are placed at the end of the line in *non-empty* blocks and block structures](#r3.2.2) +* [3.3 Indentation](#c3.3) +* [3.4 Empty blocks](#c3.4) +* [3.5 Line length](#c3.5) +* [3.6 Line breaks (newlines)](#c3.6) + * [3.6.1 Each line can have a maximum of one statement](#r3.6.1) + * [3.6.2 Rules for line-breaking](#r3.6.2) +* [3.7 Using blank lines](#c3.7) +* [3.8 Horizontal space](#c3.8) + * [3.8.1 Usage of whitespace for code separation](#r3.8.1) + * [3.8.2 No spaces for horizontal alignment](#r3.8.2) +* [3.9 Enumerations](#c3.9) +* [3.10 Variable declaration](#c3.10) + * [3.10.1 Declare one variable per line](#r3.10.1) + * [3.10.2 Variables should be declared near the line where they are first used](#r3.10.2) +* [3.11 'When' expression](#c3.11) +* [3.12 Annotations](#c3.12) +* [3.13 Block comments](#c3.13) +* [3.14 Modifiers and constant values](#c3.14) + * [3.14.1 Declaration with multiple modifiers](#r3.14.1) + * [3.14.2 Separate long numerical values with an underscore](#r3.14.2) + * [3.15 Strings](#c3.15) + * [3.15.1 Concatenation of Strings](#r3.15.1) + * [3.15.2 String template format](#r3.15.2) + +[4. Variables and types](#c4) +* [4.1 Variables](#c4.1) + * [4.1.1 Do not use Float and Double types when accurate calculations are needed](#r4.1.1) + * [4.1.2 Comparing numeric float type values](#r4.1.2) + * [4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]](#r4.1.3) +* [4.2 Types](#c4.2) + * [4.2.1 Use Contracts and smart cast as much as possible](#r4.2.1) + * [4.2.2 Try to use type alias to represent types making code more readable](#r4.2.2) +* [4.3 Null safety and variable declarations](#c4.3) + * [4.3.1 Avoid declaring variables with nullable types, especially from Kotlin stdlib](#r4.3.1) + * [4.3.2 Variables of generic types should have an explicit type declaration](#r4.3.2) + * [4.3.3 Null-safety](#r4.3.3) + +[5. Functions](#c5) +* [5.1 Function design](#c5.1) + * [5.1.1 Avoid functions that are too long ](#r5.1.1) + * [5.1.2 Avoid deep nesting of function code blocks, limiting to four levels](#r5.1.2) + * [5.1.3 Avoid using nested functions](#r5.1.3) +* [5.2 Function arguments](#c5.2) + * [5.2.1 The lambda parameter of the function should be placed at the end of the argument list](#r5.2.1) + * [5.2.2 Number of function parameters should be limited to five](#r5.2.2) + * [5.2.3 Use default values for function arguments instead of overloading them](#r5.2.3) + +[6. Classes, interfaces, and extension functions](#c6) +* [6.1 Classes](#c6.1) + * [6.1.1 Denoting a class with a single constructor](#r6.1.1) + * [6.1.2 Prefer data classes instead of classes without any functional logic](#r6.1.2) + * [6.1.3 Do not use the primary constructor if it is empty or useless](#r6.1.3) + * [6.1.4 Do not use redundant init blocks in your class](#r6.1.4) + * [6.1.5 Explicit supertype qualification](#r6.1.5) + * [6.1.6 Abstract class should have at least one abstract method](#r6.1.6) + * [6.1.7 When using the "implicit backing property" scheme, the name of real and back property should be the same](#r6.1.7) + * [6.1.8 Avoid using custom getters and setters](#r6.1.8) + * [6.1.9 Never use the name of a variable in the custom getter or setter (possible_bug)](#r6.1.9) + * [6.1.10 No trivial getters and setters are allowed in the code](#r6.1.10) + * [6.1.11 Use 'apply' for grouping object initialization](#r6.1.11) +* [6.2 Classes](#c6.2) + * [6.2.1 Use extension functions for making logic of classes less coupled](#r6.2.1) + * [6.2.2 No extension functions with the same name and signature if they extend base and inheritor classes (possible_bug)](#r6.2.2) +* [6.3 Interfaces](#c6.3) +* [6.4 Objects](#c6.4) + * [6.4.1 Instead of using utility classes/objects, use extensions](#r6.4.1) + * [6.4.2 Objects should be used for Stateless Interfaces](#r6.4.2) From 0583b0741e1e09087bb3f69f8000652bca63c8de Mon Sep 17 00:00:00 2001 From: vtchem Date: Fri, 18 Dec 2020 16:18:44 +0300 Subject: [PATCH 15/18] Reviewed changes for the Code Style guide ### What's done: Edited the TOC and requested review. --- info/guide/guide-TOC.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/info/guide/guide-TOC.md b/info/guide/guide-TOC.md index 82402abbcb..ec5ef6e66d 100644 --- a/info/guide/guide-TOC.md +++ b/info/guide/guide-TOC.md @@ -19,9 +19,9 @@ I [Preface](#c0) [2. Comments](#c2) * [2.1 General form of Kdoc](#c2.1) - * [Using KDoc for the public, protected, or internal code elements](#r2.1.1) - * [Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2) - * [Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3) + * [2.1.1 Using KDoc for the public, protected, or internal code elements](#r2.1.1) + * [2.1.2 Describing methods that have arguments, a return value, or can throw an exception in the KDoc block](#r2.1.2) + * [2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order.](#r2.1.3) * [2.2 Adding comments on the file header](#c2.2) * [2.3 Comments on the function header](#c2.3) * [2.4 Code comments](#c2.4) From bc23a7198dcd7deb0aabb00fc0fba22419b7fe5d Mon Sep 17 00:00:00 2001 From: vtchem Date: Fri, 18 Dec 2020 16:20:39 +0300 Subject: [PATCH 16/18] Reviewed changes for the Code Style guide ### What's done: Edited the TOC and requested review. --- info/guide/guide-chapter-1.md | 20 ++++++++++---------- info/guide/guide-chapter-3.md | 6 +++--- info/guide/guide-chapter-4.md | 8 ++++---- info/guide/guide-chapter-6.md | 8 ++++---- 4 files changed, 21 insertions(+), 21 deletions(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index cb5ababec5..4c9b80da98 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -4,9 +4,9 @@ In programming, it is not always easy to meaningfully and appropriately name var Note: The source file encoding format (including comments) must be UTF-8 only. The ASCII horizontal space character (0x20, that is, space) is the only permitted whitespace character. Tabs should not be used for indentation. -### 1.1 Identifier names +### 1.1 Identifiers This section describes the general rules for naming identifiers. -#### 1.1.1 Identifiers naming conventions +// #### 1.1.1 Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. @@ -66,9 +66,9 @@ Note that prefixing can also negatively affect the style and the auto-generation | Exceptions | Same as class names, but with a suffix Exception, for example: `AccessException` and `NullPointerException`| -### 1.2 Packages names +### 1.2 Packages -#### Rule 1.2.1 Package names dots +// #### Rule 1.2.1 Package names dots Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. Each file should have a `package` directive. Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. @@ -86,8 +86,8 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces -This section describes the general rules for naming classes, enumerations, and interfaces. -### 1.3.1 Classes, enumerations, interface names use Camel case +//This section describes the general rules for naming classes, enumerations, and interfaces. +//### 1.3.1 Classes, enumerations, interface names use Camel case Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below: 1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`). @@ -113,8 +113,8 @@ class Order {} ### 1.4 Functions -This section describes the general rules for naming functions. -### 1.4.1 Function names should be in camel case +// This section describes the general rules for naming functions. +// ### 1.4.1 Function names should be in camel case Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. @@ -164,8 +164,8 @@ fun addKeyListener(Listener) 2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. ### 1.5 Constants -This section describes the general rules for naming constraints. -### 1.5.1 Using UPPER case and underscore characters in a constraint name +//This section describes the general rules for naming constraints. +// ### 1.5.1 Using UPPER case and underscore characters in a constraint name Constant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. 2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants. diff --git a/info/guide/guide-chapter-3.md b/info/guide/guide-chapter-3.md index 183944f5b6..5e47c6cdf9 100644 --- a/info/guide/guide-chapter-3.md +++ b/info/guide/guide-chapter-3.md @@ -311,7 +311,7 @@ Each one of these characters represents two narrow characters. ### 3.6 Line breaks (newlines) This section contains the rules and recommendations on using line breaks. -#### 3.6.1 Each line can have a maximum of one statement. +#### 3.6.1 Each line can have a maximum of one statement Each line can have a maximum of one code statement. This recommendation prohibits the use of code with `;` because it decreases code visibility. **Invalid example:** @@ -628,7 +628,7 @@ enum class ComparisonResult { ### 3.10 Variable declaration This section describes rules for the declaration of variables. -#### 3.10.1 Declare one variable per line. +#### 3.10.1 Declare one variable per line Each property or variable must be declared on a separate line. @@ -637,7 +637,7 @@ Each property or variable must be declared on a separate line. val n1: Int; val n2: Int ``` -#### 3.10.2 Variables should be declared near the line where they are first used. +#### 3.10.2 Variables should be declared near the line where they are first used Declare local variables close to the point where they are first used to minimize their scope. This will also increase the readability of the code. Local variables are usually initialized during their declaration or immediately after. The member fields of the class should be declared collectively (see [Rule 3.1.2](#r3.1.2) for details on the class structure). diff --git a/info/guide/guide-chapter-4.md b/info/guide/guide-chapter-4.md index f6ebc67a23..2b19c4ebc8 100644 --- a/info/guide/guide-chapter-4.md +++ b/info/guide/guide-chapter-4.md @@ -65,7 +65,7 @@ if (abs(foo - bar) > 1e-6f) { } ``` -#### 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR]. +#### 4.1.3 Try to use 'val' instead of 'var' for variable declaration [SAY_NO_TO_VAR] Variables with the `val` modifier are immutable (read-only). Using `val` variables instead of `var` variables increases code robustness and readability. @@ -75,7 +75,7 @@ However, in some scenarios with loops or accumulators, only `var`s are permitted ### 4.2 Types This section provides recommendations for using types. -#### 4.2.1: Use Contracts and smart cast as much as possible. +#### 4.2.1: Use Contracts and smart cast as much as possible The Kotlin compiler has introduced [Smart Casts](https://kotlinlang.org/docs/reference/typecasts.html#smart-casts) that help reduce the size of code. @@ -123,7 +123,7 @@ fun foo(s: String?) { } ``` -#### 4.2.2: Try to use type alias to represent types making code more readable. +#### 4.2.2: Try to use type alias to represent types making code more readable Type aliases provide alternative names for existing types. If the type name is too long, you can replace it with a shorter name, which helps to shorten long generic types. @@ -152,7 +152,7 @@ typealias Predicate = (T) -> Boolean ### 4.3 Null safety and variable declarations Kotlin is declared as a null-safe programming language. However, to achieve compatibility with Java, it still supports nullable types. -#### Recommendation 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib. +#### 4.3.1: Avoid declaring variables with nullable types, especially from Kotlin stdlib To avoid `NullPointerException` and help the compiler prevent Null Pointer Exceptions, avoid using nullable types (with `?` symbol). **Invalid example**: diff --git a/info/guide/guide-chapter-6.md b/info/guide/guide-chapter-6.md index dbb410c7e6..ba7aff7765 100644 --- a/info/guide/guide-chapter-6.md +++ b/info/guide/guide-chapter-6.md @@ -310,7 +310,7 @@ class A { } ``` -#### Use 'apply' for grouping object initialization +#### 6.1.11 Use 'apply' for grouping object initialization In Java, before functional programming became popular, many classes from common libraries used the configuration paradigm. To use these classes, you had to create an object with the constructor with 0-2 arguments and set the fields needed to run the object. In Kotlin, to reduce the number of dummy code line and to group objects [`apply` extension](https://kotlinlang.org/api/latest/jvm/stdlib/kotlin/apply.html) was added: @@ -390,7 +390,7 @@ fun main() { printClassName(B()) } ``` -### 6.3 Interfaces +### 6.3 Interfaces An `Interface` in Kotlin can contain declarations of abstract methods, as well as method implementations. What makes them different from abstract classes is that interfaces cannot store state. They can have properties, but these need to be abstract or to provide accessor implementations. @@ -400,7 +400,7 @@ In Kotlin and Java, the interface is the main presentation means of application ### 6.4 Objects This section describes the rules of using objects in code. -#### 6.4.1 Instead of using utility classes/objects, use extensions. +#### 6.4.1 Instead of using utility classes/objects, use extensions Avoid using utility classes/objects; use extensions instead. As described in [6.2 Extension functions](#c6.2), using extension functions is a powerful method. This enables you to avoid unnecessary complexity and class/object wrapping and use top-level functions instead. @@ -423,7 +423,7 @@ fun String.stringInfo(): Int { "myStr".stringInfo() ``` -#### 6.4.2 Objects should be used for Stateless Interfaces. +#### 6.4.2 Objects should be used for Stateless Interfaces Kotlin’s objects are extremely useful when you need to implement some interface from an external library that does not have any state. There is no need to use classes for such structures. From 4481aa50f45ce9f881199f4e8e87edceba88eb8b Mon Sep 17 00:00:00 2001 From: vtchem Date: Fri, 18 Dec 2020 16:22:40 +0300 Subject: [PATCH 17/18] Reviewed changes for the Code Style guide ### What's done: Edited the material and requested review. --- info/guide/diktat-coding-convention.md | 32 ++++++++++++++------------ 1 file changed, 17 insertions(+), 15 deletions(-) diff --git a/info/guide/diktat-coding-convention.md b/info/guide/diktat-coding-convention.md index 49a71cc5ec..5c61cd630f 100644 --- a/info/guide/diktat-coding-convention.md +++ b/info/guide/diktat-coding-convention.md @@ -6,7 +6,7 @@ | Chapter | Content | | ------------------- | ------------------------------------------------------------ | -| [0. Preface](#c0.1) | [Purpose](#c0.1), [General principles](#c0.2), [Terminology](#c0.3), [Exceptions](#c0.4) | +| [0. Preface](c0.1) | [Purpose](#c0.1), [General principles](#c0.2), [Terminology](#c0.3), [Exceptions](#c0.4) | | [1. Naming](#c1) | [Identifiers](#c1.1), [Package names](#c1.2), [Classes, enumeration and interfaces](#c1.3), [Functions](#c1.4), [Constants](#c1.5), [Variables](#c1.6) | | [2. Docs](#c2) | [Kdoc](#c2.1), [File header](#c2.2), [Comments on function header ](#c2.3), [Code comments](#c2.4) | | [3. General formatting](#c3) | [File-related rules](#c3.1), [Braces](#c3.2), [Indentation](#c3.3), [Empty blocks](#c3.4), [Line length](#c3.5), [Line breaks (newlines)](#c3.6), [Blank lines](#c3.7), [Horizontal space](#c3.8), [Enumerations](#c3.9), [Variable declaration](#c3.10), [When expression](#c3.11), [Annotations](#c3.12), [Layout of comments](#c3.13), [Modifiers and constant values](#c3.14), [Strings](#c3.15)| @@ -16,6 +16,8 @@ | [7. Kotlin & Java](#c7) | | +Here's a useful method. Should produce clickable references in any MarkDown editor. + ## Preface @@ -88,7 +90,7 @@ Note: The source file encoding format (including comments) must be UTF-8 only. T ### 1.1 Identifier names -### Rule 1.1.1: Identifiers naming conventions +### 1.1.1: Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. @@ -353,7 +355,7 @@ It is also shown in the following single-line form: ``` Use a single-line form when you store the entire KDoc block in one line (and there is no KDoc mark @XXX). For detailed instructions on how to use KDoc, refer to [Official Document](https://docs.oracle.com/en/Kotlin/Kotlinse/11/tools/KDoc.html). -### Rule 2.1.1: KDoc is used for each public, protected or internal code element +### 2.1.1: KDoc is used for each public, protected or internal code element At a minimum, KDoc should be used for every public, protected, or internal decorated class, interface, enumeration, method, and member field (property). Other code blocks can also have KDocs if needed. @@ -406,7 +408,7 @@ fun isEmptyList(list: List) = list.size == 0 Note: You can skip KDocs for a method's override if it is almost the same as the superclass method. -### Rule 2.1.2: When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc. +### 2.1.2 When the method has arguments, return value, can throw exceptions, etc., it must be described in the KDoc block: with @param, @return, @throws, etc. **Valid examples**: @@ -441,7 +443,7 @@ Note: You can skip KDocs for a method's override if it is almost the same as the } ``` -### Rule 2.1.3: Only one space between the Kdoc tag and content. Tags are arranged in the order. +### 2.1.3 Only one space between the Kdoc tag and content. Tags are arranged in the order. There should be only one space between the Kdoc tag and content. Tags are arranged in the following order: @param, @return, and @throws. Therefore, Kdoc should contain the following: @@ -488,7 +490,7 @@ Other KDoc tags (such as @param type parameters and @see.) can be added as follo */ ``` ### 2.2 Comments to the file header -### Rule 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. +### 2.2.1: Comments on the file header must include copyright information, without the creation date and author's name (use VCS for history management instead). The content inside files that contain multiple or no classes should also be described. Comments on the file header should be placed before the package name and imports. If you need to add more content to the comment, subsequently add it in the same format. @@ -523,7 +525,7 @@ The following factors should be considered when writing the file header or comme ### 2.3 Comments on the function header -### Rule 2.3.1: Do not make unnecessary and useless comments. +### 2.3.1 Do not make unnecessary and useless comments. Comments on the function header are placed above function declarations or definitions. A newline should not exist between a function declaration and its Kdoc. Use the preceding [KDoc](#c2.1) style rules. As stated in Chapter 1, the function name should reflect its functionality as much as possible. Therefore, in the Kdoc, try to describe the functionality that is not mentioned in the function name. @@ -532,7 +534,7 @@ Avoid unnecessary comments on dummy coding. The function header comment's content is optional, but not limited to function description, return value, performance constraints, usage, memory conventions, algorithm implementation, reentrant requirements, etc. ### 2.4 Code comments -### Rule 2.4.1: Add a blank line between the body of the comment and Kdoc tag-blocks. +### 2.4.1 Add a blank line between the body of the comment and Kdoc tag-blocks. It is a good practice to add a blank line between the body of the comment and Kdoc tag-blocks. Also, consider the following rules: - There must be one space between the comment character and the content of the comment - There must be a newline between a Kdoc and presiding code @@ -613,7 +615,7 @@ val someVal = if (nr % 15 == 0) { val x = 0 // this is a comment ``` -### Rule 2.4.2: Do not comment on unused code blocks +### 2.4.2 Do not comment on unused code blocks Do not comment on unused code blocks, including imports. Delete these code blocks immediately. A code is not used to store history. Git, svn, or other VCS tools should be used for this purpose. Unused imports increase the coupling of the code and are not conducive to maintenance. The commented out code cannot be appropriately maintained. @@ -621,7 +623,7 @@ In an attempt to reuse the code, there is a high probability that you will intro The correct approach is to delete the unnecessary code directly and immediately when it is not used anymore. If you need the code again, consider porting or rewriting it as changes could have occurred since you first commented on the code. -### Recommendation 2.4.3: Code delivered to the client should not contain TODO/FIXME comments. +### 2.4.3 Code delivered to the client should not contain TODO/FIXME comments. The code officially delivered to the client typically should not contain TODO/FIXME comments. `TODO` comments are typically used to describe modification points that need to be improved and added. For example, refactoring FIXME comments are typically used to describe known defects and bugs that will be subsequently fixed and are not critical for an application. They should all have a unified style to facilitate the unified text search processing. @@ -636,13 +638,13 @@ At a version development stage, these annotations can be used to highlight the i # 3. General formatting (typesetting) ### 3.1 File-related rules -### Rule 3.1.1: Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines). +### 3.1.1 Avoid files that are too long. Files should not exceed 2000 lines (non-empty and non-commented lines). If the file is too long and complex, it should be split into smaller files, functions, or modules. It is recommended to horizontally or vertically split the file according to responsibilities or hierarchy of its parts. The only exception to this rule is code generation - the auto-generated files that are not manually modified can be longer. -### Rule 3.1.2: Code blocks in the source file should be separated by one blank line and should be in the proper order. +### 3.1.2 Code blocks in the source file should be separated by one blank line and should be in the proper order. A source file contains code blocks in the following order: copyright, package name, imports, and top-level classes. They should be separated by one blank line. a) Code blocks should be in the following order: @@ -661,7 +663,7 @@ d) **Recommendation**. One `.kt` source file should contain only one class decla e) Avoid empty files that do not contain the code or contain only imports/comments/package name -### Recommendation 3.1.3: Import statements order. +### 3.1.3 Import statements order. From top to bottom, the order is the following: 1. Android @@ -691,7 +693,7 @@ import kotlin.system.exitProcess // kotlin standard library import kotlinx.coroutines.* // official kotlin extension library ``` -### Recommendation 3.1.4: The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. +### 3.1.4 The declaration parts of class-like code structures (class, interface, etc.) should be placed in the order. The declaration parts of class-like code structures (class, interface, etc.) should be in the following order: compile-time constants (for objects), class properties, late-init class properties, init-blocks, constructors, public methods, internal methods, protected methods, private methods, and companion object. Blank lines should separate their declaration. Notes: @@ -714,7 +716,7 @@ All variants of a `(private) val` logger should be placed in the beginning of th ### 3.2 Braces -### Rule 3.2.1: Braces must be used in conditional statements and loop blocks. +### 3.2.1: Braces must be used in conditional statements and loop blocks. Braces should always be used in `if`, `else`, `for`, `do`, and `while` statements, even if the program body is empty or contains only one statement. In special Kotlin `when` statements, you do not need to use braces for single-line statements. From f9d3b0ba4726ac624ae46c2da9f4fbcf19adde88 Mon Sep 17 00:00:00 2001 From: Andrey Kuleshov Date: Mon, 21 Dec 2020 11:23:43 +0300 Subject: [PATCH 18/18] Update guide-chapter-1.md --- info/guide/guide-chapter-1.md | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/info/guide/guide-chapter-1.md b/info/guide/guide-chapter-1.md index 4c9b80da98..ae8237d95d 100644 --- a/info/guide/guide-chapter-1.md +++ b/info/guide/guide-chapter-1.md @@ -6,7 +6,7 @@ Note: The source file encoding format (including comments) must be UTF-8 only. T ### 1.1 Identifiers This section describes the general rules for naming identifiers. -// #### 1.1.1 Identifiers naming conventions +#### 1.1.1 Identifiers naming conventions For identifiers, use the following naming conventions: 1. All identifiers should use only ASCII letters or digits, and the names should match regular expressions `\w{2,64}`. @@ -68,7 +68,7 @@ Note that prefixing can also negatively affect the style and the auto-generation ### 1.2 Packages -// #### Rule 1.2.1 Package names dots +#### Rule 1.2.1 Package names dots Package names are in lower case and separated by dots. Code developed within your company should start with `your.company.domain.` Numbers are permitted in package names. Each file should have a `package` directive. Package names are all written in lowercase, and consecutive words are concatenated together (no underscores). Package names should contain both the product or module names and the department (or team) name to prevent conflicts with other teams. Numbers are not permitted. For example: `org.apache.commons.lang3`, `xxx.yyy.v2`. @@ -86,8 +86,8 @@ package your.company.domain.mobilecontrol.views ### 1.3 Classes, enumerations, interfaces -//This section describes the general rules for naming classes, enumerations, and interfaces. -//### 1.3.1 Classes, enumerations, interface names use Camel case +This section describes the general rules for naming classes, enumerations, and interfaces. +### 1.3.1 Classes, enumerations, interface names use Camel case Classes, enumerations, and interface names use `UpperCamelCase` nomenclature. Follow the naming rules described below: 1. A class name is usually a noun (or a noun phrase) denoted using the camel case nomenclature, such as UpperCamelCase. For example: `Character` or `ImmutableList`. An interface name can also be a noun or noun phrase (such as `List`) or an adjective or adjective phrase (such as `Readable`). @@ -113,8 +113,8 @@ class Order {} ### 1.4 Functions -// This section describes the general rules for naming functions. -// ### 1.4.1 Function names should be in camel case +This section describes the general rules for naming functions. +### 1.4.1 Function names should be in camel case Function names should use `lowerCamelCase` nomenclature. Follow the naming rules described below: 1. Function names are usually verbs or verb phrases denoted with the camel case nomenclature (`lowerCamelCase`). For example: `sendMessage`, `stopProcess`, or `calculateValue`. @@ -164,8 +164,8 @@ fun addKeyListener(Listener) 2. An underscore (`_`) can be included in the JUnit test function name and should be used as a separator. Each logical part is denoted in `lowerCamelCase`, for example, a typical pattern of using underscore: `pop_emptyStack`. ### 1.5 Constants -//This section describes the general rules for naming constraints. -// ### 1.5.1 Using UPPER case and underscore characters in a constraint name +This section describes the general rules for naming constraints. +### 1.5.1 Using UPPER case and underscore characters in a constraint name Constant names should be in UPPER case, words separated by underscore. The general constant naming conventions are listed below: 1. Constants are attributes created with the `const` keyword or top-level/`val` local variables of an object that holds immutable data. In most cases, constants can be identified as a `const val` property from the `object`/`companion object`/file top level. These variables contain fixed constant values that typically should never be changed by programmers. This includes basic types, strings, immutable types, and immutable collections of immutable types. The value is not constant for the object, which state can be changed. 2. Constant names should contain only uppercase letters separated by an underscores. They should have a val or const val modifier to make them final explicitly. In most cases, if you need to specify a constant value, then you need to create it with the "const val" modifier. Note that not all `val` variables are constants.