Kotlin/kotlin-style-guide

Function expression body formatting

yole opened this issue ยท 9 comments

yole commented

If the function has an expression body that doesn't fit in the same line as the declaration, put the = sign on the first line. Indent the expression body by 4 spaces.

fun f(x: String) =
    x.length

If the expression body does not fit on one line, prefer using a block body instead.

If the body of a function is an if, when, try or object expression, the expression is not additionally indented; the closing brace of the expression is on the same indentation level as where the function closing curly brace would be.

fun f(x: String) = when(x) {
    "foo" -> ...
    else -> ...
}

However, if the function header is long and can't be fit on the same line as function declaration (because the declaration is too long, the condition is complex, or the object expression needs a complex set of super-types), then the expression is on a new line and the closing brace of the expression is on the same indentation level as the head of the expression:

fun f(x: String, y: String) = 
    when(x.equals(y, ignoreCase = true)) {
        "foo" -> ...
        else -> ...
    }

I think it's worth to put the = sign on the first line

  • There are already a lot of declaration with breaks after = (~ 500) in our project
  • Such break rule fits better in case of multiline expression:
fun foo(args: Array<String>) =
        args.getOrNull(0)?.let { println(it) }
        ?: Unit // expression starts at the same indentation level

I'm in favor of putting the = sign on the new line.

I changed my mind. I'm in favor of putting the = sign on the same line and the expression on a new line.

Well, to be honest, we have approximately 400 functions with = on the new line

yole commented

One argument in favor of putting = on the previous line is the consistency with val:

val VeryLongString =
    "StringValue"

vs

val VeryLongString
    = "StringValue"

I think the former looks clearly better.

I think that = before function expression body is similar to { in block body.
Your eye usually skip it when you read it. It doesn't really deserve spotlight.
To me,

val veryLongAndMeaningfulName 
    = "value"

reads like "I already know it is going to be an initializer, because it is something indented after val".

I find it very hard to read when the start of a conditional expression is on the first line after a long function declaration:

fun f(firstParameter: String, secondParameter: List<String>) = when(x) {
    "foo" -> ...
    else -> ...
}

A solution for this is to use return when(x) in a block body

If the body of a function is an if, when or object expression, and it can't be fit on the same line as function declaration (because the declaration is too long, the condition is complex, or the object expression needs a complex set of super-types), then the expression is on a new line and the closing brace of the expression is on the same indentation level as the head of the expression:

fun f(x: String, y: String) = 
    when(x.equals(y, ignoreCase = true)) {
        "foo" -> ...
        else -> ...
    }

When reading a function declaration with expression body I usually read the method signature and at some point I skip (fast forward) to the = sign which delimits the method start. This works just the same with a = sign ending the first line. After skipping to the sign it is clear to me that the actual method body begins on the new line, with the typical method body indentation.

Also, if a method has a block body, the opening curly brace is at the end of the line. The method body starts at the new line with the same method body indentation. Thus having the = sign at the end of the first line also has the advantage that the begin if a method body its indentation is the same for both styles.

Hence I vote for the = sign at the end of the line.

I went through my project and replaced usages of

fun foo()
    = expression.call()

with

fun foo() =
    expression.call()

I find this style to be better, too.

As I see it, there's consensus this style is better, right? In that case we should create an issue for the formatter to automatically place the = sign.