DEV Community

Kiolk
Kiolk

Posted on

Small Thing, Big Impact

Trailing comma illustration
Original by author

I will tell about a very obvious topic: trailing comma. Maybe many of you handle this and now even care about it, because it looks very natural to put a comma after the last parameter when you define a function or a class, or call them in the code. It is just my self-reflection, and I try to formulate and finalize this moment for myself.

Trailing comma is the basic concept now, but we need slightly back to understand why it rise. First programming language where comma as separator allows in syntax count the first version of Perl designed by Larry Wall (December 1987). It wasn't directly mentioned in documentation, but this syntax didn't cause any problem. It was explicitly documented only in Perl 4 (1991).

After this trailing comma step by step as a concept start appears in many languages, in most cases in limited scope (Python, Ruby, JavaScript, C#). This picture quickly change after invention Git in 2005. With increasing popularity this version control system, trailing comma transformed just from syntax convenience into a team collaboration optimization which allow small diff and less number of merge conflicts. Since this time most of modern languages have support very wide trailing comma (Go, Rust, Swift, Kotlin, TypeScript) or added limited support (C++, PHP).

Trailing comma makes diff smallTrailing comma make diff small. Original by author

Interesting fact, that trailing comma is very limited present in Java. From Java 4 it is allowed in enums, and from Java 8 in array initializers and annotation arguments. In Kotlin trailing appears from version 1.4 (2020).

Timeline of Trailing Comma Acceptance in Programming Languages
Timeline of Trailing Comma Acceptance in Programming Languages. Created by NANO BANANO

So, why should we use a trailing comma when we write the code? To be honest, nothing forces us to do this. It does not matter whether we do or don't do this, our code will be successfully compiled and the program will be executed. The problem arises when we start working in a team on the same code base, especially when we try to do some stuff in parallel. Simple changes like adding new parameters in the constructor can cause a merge conflict in a place where it shouldn't be present logically, because this parameter itself doesn't conflict with the existing logic, or the logic was changed before. And this is really time wasting: solving merge conflicts, rerunning pipelines, or just switching branches on the local machine takes time (stashing progress, switching the branch itself, syncing the project, etc.).

If you don't care about trailing commas in your project, I am pretty sure you will face this problem many times on a repetitive basis.

The solution for this is very simple: just enable ktlint to force it to treat a missing comma as an error, and block the ability to merge a PR if this issue appears.

To make this rule obligatory for every team member, you should configure the .editorconfig file properly, which will be stored under version control and synchronize the configuration. You couldn't miss this, because these rules are enabled by default and will be active after ktlint configuration. If you want to mark this explicitly, you can add flags in the .editorconfig file.

…
ij_kotlin_allow_trailing_comma = true
ij_kotlin_allow_trailing_comma_on_call_site = true
…
Enter fullscreen mode Exit fullscreen mode

As you can see, treating missing trailing commas is defined by two flags. One of them, ij_kotlin_allow_trailing_comma, is responsible for the trailing comma in declarations (constructor parameters, function parameters, etc.). The second one, ij_kotlin_allow_trailing_comma_on_call_site, is responsible for the trailing comma in calls, when we invoke a constructor, function, etc. In Kotlin code style, it is strongly recommended to use a trailing comma in declarations, but for calls it depends on team convention.

Trailing commas are entirely optional — your code will still work without them. The Kotlin style guide encourages the use of trailing commas at the declaration site and leaves it at your discretion for the call site. Kotlin coding conventions

I personally prefer to use trailing commas in both cases for consistency and for preventing merge conflicts, which I mentioned above. After ktlint configuration, you can simply format the entire codebase to add trailing commas in every place where they should be, using the simple command ./gradlew ktlintFormat, which does this for you automatically, and you can store all changes as a single commit. I would recommend doing this quickly and forcing the entire team to rebase on develop, because at the start it can lead to several merge conflicts when teammates pull the latest develop, especially if there are branches with a long history.

In addition to ktlint, you can enable adding the trailing comma as part of formatting behavior in Android Studio. Go to Settings → Editor → Code Style → Kotlin → Other (tab) → enable Use trailing comma. After this, every time you reformat code with Option + Command + L, a trailing comma will be added in the right place. By default, the trailing comma will be added only in declarations, but if you want to add it at call sites, you should add ij_kotlin_allow_trailing_comma_on_call_site = true flag in the .editorconfig file.

Another case where it is very useful is when we have several parameters and in one of the moments we need to sort them for any reason (I use keys: Option + Command + Arrow Up/Down). If this sorting operation involves the last parameters, in most of the cases it causes an error. It is easy to fix, but takes time to navigate and type.

Sorting parameters with and without a trailing comma
Sorting parameters with and without a trailing comma

Also it makes code more consistent, where every line in the list of parameters looks similar, ready for future modification or even copy/paste.

The trailing comma itself does not affect the final compiled code and can be safely added to any project. It is a small improvement, but it makes your code more convenient and less prone to merge conflicts.

It is done, I finalize this question for myself, and will use this article as reference next time, when adding some proof for the need to use trailing commas in Kotlin code.

Top comments (0)