Kotlin
Coding Conventions
Swift
|
Naming rules
|
open class DeclarationProcessor { /*...*/ }
object EmptyDeclarationProcessor : DeclarationProcessor() { /*...*/ }
|
class DeclarationProcessor { /*...*/ }
let emptyDeclarationProcessor : DeclarationProcessor.shared()
|
Function names
|
fun processDeclarations() { /*...*/ }
var declarationCount = 1
|
func processDeclarations() { /*...*/ }
var declarationCount = 1
|
interface Foo { /*...*/ }
class FooImpl : Foo { /*...*/ }
fun Foo(): Foo { return FooImpl() }
|
protocol Foo { /*...*/ }
class FooImpl : Foo { /*...*/ }
func foo() -> Foo { return FooImpl() }
|
Names for test methods
|
class MyTestCase {
@Test fun `ensure everything works`() { /*...*/ }
@Test fun ensureEverythingWorks_onAndroid() { /*...*/ }
}
|
class MyTestCase: XCTestCase {
func testLogin() throws { /* */ }
}
|
Property names
|
const val MAX_COUNT = 8
val USER_NAME_FIELD = "UserName"
|
Names of types and protocols are UpperCamelCase. Everything else is lowerCamelCase.
|
val mutableCollection: MutableSet<String> = HashSet()
|
var mutableCollection = Set<String>()
|
val PersonComparator: Comparator<Person> = /*...*/
|
let personComparator: Comparator<Person> = /*...*/
|
Names for backing properties
|
class C {
private val _elementList = mutableListOf<Element>()
val elementList: List<Element>
get() = _elementList
}
|
class C {
private var _elementList = [Int]()
var elementList: [Int] {
get { return _elementList }
}
}
|
Formatting
|
if (elements != null) {
for (element in elements) {
// ...
}
}
|
if elements != nil {
for element in elements! {
// ...
}
}
|
Horizontal whitespace
|
class A(val x: Int)
fun foo(x: Int) { ... }
fun bar() {
foo(1)
}
|
class A {
A(x: Int) {
}
}
func foo(x: Int) { ... }
func bar() {
foo(x: 1)
}
|
Colon
|
abstract class Foo<out T : Any> : IFoo {
abstract fun foo(a: Int): T
}
class FooImpl : Foo() {
constructor(x: String) : this(x) { /*...*/ }
val x = object : IFoo { /*...*/ }
}
|
protocol IFoo {}
class AImpl: IFoo { /*...*/ }
protocol Foo: IFoo {
associatedtype T
func foo(a: Int) -> T
}
class FooImpl: Foo {
init(x: String) { /*...*/ }
func foo(a: Int) -> String { /*...*/ }
let x: IFoo = AImpl()
}
|
Class header formatting
|
class Person(id: Int, name: String)
|
class Person {
var id: Int = 0
var name: String = ""
}
|
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name) { /*...*/ }
|
class Human {
var id: Int = 0
var name: String = ""
init(id: Int, name: String) {
self.id = id
self.name = name
}
}
class Person: Human {
var surname: String = ""
init(id: Int, name: String, surname: String) {
super.init(id: id, name: name)
}
}
|
class Person(
id: Int,
name: String,
surname: String
) : Human(id, name),
KotlinMaker { /*...*/ }
|
class Person: Human, KotlinMaker {
var surname: String = ""
init(id: Int, name: String, surname: String) {
super.init(id: id, name: name)
}
/*...*/
}
|
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne {
fun foo() { /*...*/ }
}
|
class MyFavouriteVeryLongClassHolder:
MyLongHolder,
SomeOtherInterface,
AndAnotherOne {
typealias Type = MyFavouriteVeryLongClass
func foo() { /*...*/ }
}
|
class MyFavouriteVeryLongClassHolder :
MyLongHolder<MyFavouriteVeryLongClass>(),
SomeOtherInterface,
AndAnotherOne
{
fun foo() { /*...*/ }
}
|
class MyFavouriteVeryLongClassHolder:
MyLongHolder,
SomeOtherInterface,
AndAnotherOne
{
typealias Type = MyFavouriteVeryLongClass
func foo() { /*...*/ }
}
|
Modifiers
|
public / protected / private / internal
expect / actual
final / open / abstract / sealed / const
external
override
lateinit
tailrec
vararg
suspend
inner
enum / annotation / fun // as a modifier in `fun interface`
companion
inline
infix
operator
data
|
open
public
internal
fileprivate
private
|
@Named("Foo")
private val foo: Foo
|
@propertyWrapper
struct SomeWrapper { /*...*/ }
|
Annotation formatting
|
@Target(AnnotationTarget.PROPERTY)
annotation class JsonExclude
|
@available(iOS 10.0, macOS 10.12, *)
class MyClass {
// class definition
}
|
@JsonExclude @JvmField
var x: String
|
|
@Test fun foo() { /*...*/ }
|
@objc func foo() { /*...*/ }
|
File annotations
|
/** License, copyright and whatever */
@file:JvmName("FooBar")
package foo.bar
|
|
Function formatting
|
fun longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType,
): ReturnType {
// body
}
|
func longMethodName(
argument: ArgumentType = defaultValue,
argument2: AnotherArgumentType,
): ReturnType {
// body
}
|
fun foo(): Int { // bad
return 1
}
fun foo() = 1 // good
👏
|
func foo() -> Int {
return 1
}
|
Expression body formatting
|
fun f(x: String, y: String, z: String) =
veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z)
|
func f(x: String, y: String, z: String) {
veryLongFunctionCallWithManyWords(andLongParametersToo(), x, y, z)
}
|
Property formatting
|
val isEmpty: Boolean get() = size == 0
|
var isEmpty: Bool {
get { size == 0 }
}
|
val foo: String
get() { /*...*/ }
|
var foo: String {
get { /*...*/ }
}
|
private val defaultCharset: Charset? =
EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
|
private let defaultCharset: Charset? = {
EncodingRegistry.getInstance().getDefaultCharsetForPropertiesFiles(file)
}()
|
Formatting control flow statements
|
if (!component.isSyncing &&
!hasAnyKotlinRuntimeInScope(module)
) {
return createKotlinNotConfiguredPanel(module)
}
|
if (!component.isSyncing &&
!hasAnyKotlinRuntimeInScope(module)
) {
createKotlinNotConfiguredPanel(module)
}
|
if (condition) {
// body
} else {
// else part
}
try {
// body
} finally {
// cleanup
}
|
if condition {
// body
} else {
// else part
}
defer {
// cleanup
}
do {
try foo()
} catch {
}
|
private fun parsePropertyValue(propName: String, token: Token) {
when (token) {
is Token.ValueToken ->
callback.visitValue(propName, token.value)
Token.LBRACE -> { // ...
}
}
}
|
private func parsePropertyValue(propName: String, token: Token) {
switch token {
case .valueToken:
callback.visitValue(propName, token.value)
case .lbrance: // ...
}
}
|
when (foo) {
true -> bar() // good
false -> { baz() } // bad
}
|
if foo {
bar()
}else {
baz()
}
|
Method call formatting
|
drawSquare(
x = 10, y = 10,
width = 100, height = 100,
fill = true
)
|
drawSquare(
x: 10, y: 10,
width: 100, height: 100,
fill: true
)
|
Chained call wrapping
|
val anchor = owner
?.firstChild!!
.siblings(forward = true)
.dropWhile { it is PsiComment || it is PsiWhiteSpace }
|
let anchor = owner
?.firstChild!
.siblings(forward: true)
.dropWhile { $0 is PsiComment || $0 is PsiWhiteSpace }
|
Lambda formatting
|
list.filter { it > 10 }
|
list.filter { $0 > 10 }
|
fun foo() {
ints.forEach lit@{
// ...
}
}
|
|
appendCommaSeparated(properties) { prop ->
val propertyValue = prop.get(obj) // ...
}
|
appendCommaSeparated(properties) { prop in
let propertyValue = prop.get(obj) // ...
}
|
foo {
context: Context,
environment: Env
->
context.configureEnv(environment)
}
|
foo { context, environment in
context.configureEnv(environment)
}
|
Trailing commas
|
class Person(
val firstName: String,
val lastName: String,
val age: Int, // trailing comma
)
|
class Person {
var firstName: String = ""
var lastName: String = ""
var age: Int = 0
}
|
Enumerations
|
enum class Direction {
NORTH,
SOUTH,
WEST,
EAST, // trailing comma
}
|
enum Direction {
case north
case south
case west
case east
}
|
Value arguments
|
fun shift(x: Int, y: Int) { /*...*/ }
shift(
25,
20, // trailing comma
)
val colors = listOf(
"red",
"green",
"blue", // trailing comma
)
|
func shift(x: Int, y: Int) { /*...*/ }
shift(
x: 25,
y: 20
)
let colors = [
"red",
"green",
"blue", // trailing comma
]
|
Class properties and parameters
|
class Customer(
val name: String,
val lastName: String, // trailing comma
)
class Customer(
val name: String,
lastName: String, // trailing comma
)
|
class Customer {
var name: String?
var lastName: String?
}
|
Function value parameters
|
fun powerOf(
number: Int,
exponent: Int, // trailing comma
) { /*...*/ }
constructor(
x: Comparable<Number>,
y: Iterable<Number>, // trailing comma
) {}
fun print(
vararg quantity: Int,
description: String, // trailing comma
) {}
|
func powerOf(
number: Int,
exponent: Int
) { /*...*/ }
init(
x: Comparable<Number>,
y: Iterable<Number>
) {}
func print(
quantity: Int...,
description: String
) {}
|
Parameters with optional type (including setters)
|
val sum: (Int, Int, Int) -> Int = fun(
x,
y,
z, // trailing comma
): Int {
return x + y + x
}
println(sum(8, 8, 8))
|
let sum: (Int, Int, Int) -> Int = { $0 + $1 + $2 }
print(sum(8, 8, 8))
|
Indexing suffix
|
class Surface {
operator fun get(x: Int, y: Int) = 2 * x + 4 * y - 10
}
fun getZValue(mySurface: Surface, xValue: Int, yValue: Int) =
mySurface[
xValue,
yValue, // trailing comma
]
|
class Surface {
subscript(x: Int, y: Int) -> Int {
2 * x + 4 * y - 10
}
}
func getZValue(mySurface: Surface, xValue: Int, yValue: Int) -> Int {
mySurface[
xValue,
yValue
]
}
|
Lambda parameters
|
fun main() {
val x = {
x: Comparable<Number>,
y: Iterable<Number>, // trailing comma
->
println("1")
}
println(x)
}
|
func main() {
let x: (Comparable<Number>, Iterable<Number>) = { x, y in
print("1")
}
print(x)
}
|
when entry
|
fun isReferenceApplicable(myReference: KClass<*>) = when (myReference) {
Comparable::class,
Iterable::class,
String::class, // trailing comma
-> true
else -> false
}
|
|
Collection literals (in annotations)
|
annotation class ApplicableFor(val services: Array<String>)
@ApplicableFor([
"serializer",
"balancer",
"database",
"inMemoryCache", // trailing comma
])
fun run() {}
|
|
Type arguments
|
fun <T1, T2> foo() {}
fun main() {
foo<
Comparable<Number>,
Iterable<Number>, // trailing comma
>()
}
|
|
Type parameters
|
class MyMap<
MyKey,
MyValue, // trailing comma
> {}
|
|
Destructuring declarations
|
data class Car(val manufacturer: String, val model: String, val year: Int)
val myCar = Car("Tesla", "Y", 2019)
val (
manufacturer,
model,
year, // trailing comma
) = myCar
val cars = listOf<Car>()
fun printMeanValue() {
var meanValue: Int = 0
for ((
_,
_,
year, // trailing comma
) in cars) {
meanValue += year
}
println(meanValue/cars.size)
}
printMeanValue()
|
|
Documentation comments
|
/**
* This is a documentation comment
* on multiple lines.
*/
|
/**
* This is a documentation comment
* on multiple lines.
*/
|
/** This is a short documentation comment. */
|
/** This is a short documentation comment. */
|
// Avoid doing this:
/**
* Returns the absolute value of the given number.
* @param number The number to return the absolute value for.
* @return The absolute value.
*/
fun abs(number: Int) { /*...*/ }
// Do this instead:
/**
* Returns the absolute value of the given [number].
*/
fun abs(number: Int) { /*...*/ }
|
|
Unit
|
fun foo() { // ": Unit" is omitted here
}
|
func foo() { // ": Void" is omitted here
}
|
String templates
|
println("$name has ${children.size} children")
|
print("\(name) has \(children.size) children")
|
Immutability
|
// Bad: use of mutable collection type for value which will not be mutated
fun validateValue(actualValue: String, allowedValues: HashSet<String>) { ... }
// Good: immutable collection type used instead
fun validateValue(actualValue: String, allowedValues: Set<String>) { ... }
// Bad: arrayListOf() returns ArrayList<T>, which is a mutable collection type
val allowedValues = arrayListOf("a", "b", "c")
// Good: listOf() returns List<T>
val allowedValues = listOf("a", "b", "c")
|
func validateValue(actualValue: String, allowedValues: Set<String>) { ... }
let allowedValues = ["a", "b", "c"]
|
Default parameter values
|
// Bad
fun foo() = foo("a")
fun foo(a: String) { /*...*/ }
// Good
fun foo(a: String = "a") { /*...*/ }
|
// Bad
func foo() {
foo(a: "a")
}
func foo(a: String) { /*...*/ }
// Good
func foo(a: String = "a") { /*...*/ }
|
Type aliases
|
typealias MouseClickHandler = (Any, MouseEvent) -> Unit
typealias PersonIndex = Map<String, Person>
|
typealias MouseClickHandler = (Any, MouseEvent) -> Void
typealias PersonIndex = Map<String, Person>
|
Named arguments
|
drawSquare(x = 10, y = 10, width = 100, height = 100, fill = true)
|
drawSquare(x: 10, y: 10, width: 100, height: 100, fill: true)
|
Using conditional statements
|
return if (x) foo() else bar()
return when(x) {
0 -> "zero"
else -> "nonzero"
}
|
return x ? foo() : bar()
switch x {
case 0:
return "zero"
default:
return "nonzero"
}
|
if (x)
return foo()
else
return bar()
when(x) {
0 -> return "zero"
else -> return "nonzero"
}
|
if x {
return foo()
}else {
return bar()
}
switch x {
case 0:
return "zero"
default:
return "nonzero"
}
|
if versus when
|
when (x) {
null -> // ...
else -> // ...
}
|
switch x {
case nil: // ...
default: // ...
}
|
Loops on ranges
|
for (i in 0..n - 1) { /*...*/ } // bad
for (i in 0 until n) { /*...*/ } // good
|
for i in 0...n-1 { /*...*/ } // bad
for i in 0..<n) { /*...*/ } // good
|
Using strings
|
assertEquals(
"""
Foo
Bar
""".trimIndent(),
value
)
val a = """if(a > 1) {
| return a
|}""".trimMargin()
|
assert("""
Foo
Bar
""" == "Foo\nBar")
let a = """
if(a > 1) {
return a
}
"""
|
Factory functions
|
class Point(val x: Double, val y: Double) {
companion object {
fun fromPolar(angle: Double, radius: Double) = Point(...)
}
}
|
class Point {
let x, y: Double = 0
static func fromPolar(angle: Double, radius: Double) {
Point(...)
}
}
|
Platform types
|
fun apiCall(): String = MyJavaApi.getProperty("name")
|
|
class Person {
val name: String = MyJavaApi.getProperty("name")
}
|
|
fun main() {
val name = MyJavaApi.getProperty("name")
println(name)
}
|
|