- Introduction
- Styling
- Source files
- Formatting
- Naming
This is a complete definition of my style guide for the Kotlin programming language.
This guide contains information about both personal uses and recommendations as well as styles and conventions not permitted.
Type - A class, interface, or object. Modifiers are not applicable here (e.g. enum class
counts as a class).
Primary type - Referring to a type in a file with multiple type, this is generally a type that is inherited by other types in the file, such as a sealed class
.
Strictly required - Something that I will throw out and literally throw up at if I see.
The main part of this document is, of course, the actual style. This contains information on what is allowed and what isn't.
A source file is a file that contains some form of source code, and these files generally end with the .kt file extension for Kotlin.
- Naming:
- If the file contains a single type (class, interface, etc.), the name of the file should be the exact name of the class
- If the file contains multiple types, the name of the file is generally the name of the type at the top (which is often what I will call here the "primary" one)
- If the file contains no types, it should be named in camelCase.
- Encoding should be in UTF-8
- Special characters:
- Whitespace should only be the ASCII horizontal space character (0x20), not any other character. This implies that tab characters must not be used for
- indentation, and that all other whitespace characters must be properly escaped.
- Escape sequences should be preferred over their octal or Unicode representation.
- Non-ASCII characters should either use their character representation, or a Unicode escape character. The former should be preferred for readability.
- Files should be ordered in the following order:
- License or copyright information, if present.
- Package statement
- Import statements
- If a type is present in the file, this should be ordered first, unless it is an internal part of the project and is used by other members within that file, such as a type that is constructed by top-level functions.
- Top-level functions and properties
- Files can optionally end with a blank line, but this is not recommended, and I personally do not do this.
The package statement is never wrapped, nor does it adhere to any column limits. This should always be a single line.
- Wildcard imports are openly permitted and, in fact, highly encouraged, as they help to reduce the amount of import statements present in a file. My personal setting for the number of types before producing a wildcard import is three.
- Import statements are also never wrapped, and do not adhere to any column limits. These should always be single lines.
- As this is Kotlin, multiple types residing in a single file is permitted, though it is highly recommended to only put types in the same file as one another:
- If it is required, such as for sealed classes. In this case, the sealed class should be put at the top of the file, and the implementations should follow.
- If they share something that should only be available to them, such as a
private
top-level function or property (asprivate
in the file context means it is accessible only to the file's members)
- The type's declaration should always begin with the type's keyword, followed by its name on the same line, then its primary constructor parameters, which can
be separated by a line break in Kotlin style (see below), followed by its parents, which may also be separated by a line break.
- An example of this:
data class Person(val name: String, val age: Int) : Comparable<Person>
- As seen above, the braces may also be omitted, and it is highly recommended to do so as well, as they are completely unnecessary.
- An example of this:
- There should always be a line break following the initial declaration before any members are declared (this is optional, but highly recommended, and what I
personally use). An example of this would be:
class MyClass { fun foo() = Unit }
This is mostly personal preference, but I personally use and recommend the following:
- Property declarations, e.g.
val
s andvar
s - Abstract functions (for abstract classes, sealed classes and interfaces)
- Public functions with a default/final functions (no overridden functions)
- Overridden functions
- Non-public functions
- Extension or backing properties (properties with no value and a custom getter, such as those used to replace
getX
methods from Java) - Nested types
- The companion object
An example of this can be seen here:
inline class IntWrapper(val value: Int) : Comparable<IntWrapper> {
val byteValue = value.toByte()
operator fun plus(other: Int) = value + other
override fun compareTo(other: IntWrapper) = value.compareTo(other.value)
private fun hash() = hashCode()
val string: String
get() = value.toString()
class IntTransformer {
fun transform(value: Int)
}
companion object {
const val ONE = 1
}
}
(I know that's a terrible example, but hey, at least it has everything in the right order)
Covers most of the actual formatting information.
Some common things:
- Expression functions are permitted, and even encouraged, for functions with a single statement. I personally take this luxury very far, and very much overuse these, which you are free to also do if you like.
- Overridden functions that you do not want to implement functionality for that return
Unit
should always be implemented asfun doNothing() = Unit
, rather thanfun doNothing() {}
. - There should be one statement per line. The semicolon (
;
) separator should not be used at all, except for in cases where you want to set avar
's setter to a different visibility, or annotate it, e.g.val myValue = 0; private set
. - The recommended column limit is 120 characters (the default in the IntelliJ IDE). Any code that exceeds this should be split per call, for example:
val string = StringBuilder("Hello") .append(' ') .append("World") .append('!') .toString()
At all times, the indentation should be exactly four spaces. This is not optional. Two spaces, or the significantly more horrifying eight spaces, are not permitted. Anywhere.
Brackets should always be in the Kernighan and Ritchie style, specifically the one true brace style (I'm not kidding, that's what it's called) variant.
Information about this style can be found on the Wikipedia page
There are three different ways you can write a single statement if statement (one that only does one thing), those being:
-
On a single line:
if (condition) return
-
On the next line without braces:
if (condition) return
-
On the next line with braces:
if (condition) { return }
-
The first one is the one that I recommend and most commonly use, unless the statement (in the above case,
return
) is too long to fit on a single line, in which the third one should be used. I believe that using a single line here helps to keep your code concise. -
The second one is not permitted under any circumstances.
-
The third one is an alternative to the first, and can be used if preferred.
In addition, the third one should be used anywhere that there is more than a single condition (of course), and there is one more exception to do with else
statements. That being that if
statements should always be braced if the entire if (condition) x else y
cannot fit on a single line cleanly like that.
if (condition) x
else y
The above is not recommended, and preferrably should not be used.
All other control flow statements are generally more than a single line anyway, so will mostly be braced, but single line for
and while
statements are
permitted.
when
statements are always braced.
Other than where it is required by the language, a single ASCII space appears in the following places:
- Separating any keyword, such as
if
,for
orcatch
, from an open parenthesis ((
). This is strictly required. - Separating any keyword, such as
else
orcatch
, from a closing curly bracket (}
). This is also strictly required. - Before any open curly bracket (
{
). - On both sides of any binary operator, such as a
+
or=
. - After
,:;
- On both sides of the double slash (
//
) that begins an end-of-line comment. Multiple spaces are permitted here, but not required.
This must not be used. Anywhere. Ever.