16

I have static function which is limited to some context eg only for docs. There are 2 alternative ways to define it as top-level function or function in an object.

1.

package com.armsoft.mtrade.data.pref

import com.armsoft.mtrade.App
import com.armsoft.mtrade.domain.model.DocSaveType

object DocPrefManager {
    private const val DOC_PREF = "DOC_PREF"

    private const val KEY_ORDER_SAVE_TYPE = "KEY_ORDER_SAVE_TYPE"

    @JvmStatic
    fun setOrderSaveType(orderSaveType: DocSaveType) {
        val context = App.getContext()
        val sharedPreferences = context.getSharedPreferences(DOC_PREF, 0)
        val editor = sharedPreferences.edit()
        editor.putString(KEY_ORDER_SAVE_TYPE, orderSaveType.getCode())
        editor.commit()
    }
}

2.

package com.armsoft.mtrade.data.pref

import com.armsoft.mtrade.App
import com.armsoft.mtrade.domain.model.DocSaveType

fun setOrderSaveType(orderSaveType: DocSaveType) {
    val context = App.getContext()
    val sharedPreferences = context.getSharedPreferences(DocPrefManager.DOC_PREF, 0)
    val editor = sharedPreferences.edit()
    editor.putString(DocPrefManager.KEY_ORDER_SAVE_TYPE, orderSaveType.getCode())
    editor.commit()
}

The advantage of top-level function that it is not wrapped in an object and disadvantage that it can be accessed from everywhere without class name prefix. Are there advantages or disadvantages or best practice for such cases?

Michael
  • 57,169
  • 9
  • 80
  • 125
Vahan
  • 3,016
  • 3
  • 27
  • 43

5 Answers5

17

The recommended practice is to never use object for creating namespaces, and to always use top-level declarations when possible. We haven’t found name conflicts to be an issue, and if you do get a conflict, you can resolve it using an import with alias.

Alexey Romanov
  • 167,066
  • 35
  • 309
  • 487
  • 3
    For those reading this accepted answer in 2023, top-level declaration is no longer officially recommended in Kotlin docs. Also read this https://discuss.kotlinlang.org/t/best-practices-for-top-level-declarations/2198/8 and this https://discuss.kotlinlang.org/t/extension-vs-member-functions/10769/7 – sergeidyga Jul 05 '23 at 13:59
6

Tip for multi-module projects:

Use the internal visibility modifier to scope a top-level function to its containing module so that it doesn't pollute the IDE auto-complete in unrelated modules.

// module A
internal fun doSomething() {
    // ...
}

// module B
doSomething() // (!) Cannot access 'doSomething': it is internal in module A
              // Does NOT show up in module B's auto-complete
Community
  • 1
  • 1
5

KotlinConf 2017 - You Can, but Should You? by Mike Gouline recommends we should use the top-level function carefully because it may cause "autocomplete pollution".

But, BTW, Andrey Breslav (as of this edit the former Team Lead of the Kotlin team) regarded the top-level function as his the most favorite language feature in KotlinConf 2018 - Closing Panel.

Ray Eldath
  • 375
  • 3
  • 13
3

Although the recommended approach is to use top-level declarations when possible, functions that are only used in specific contexts should be scoped to that context and declared in the relevant class. Top-level functions are especially useful for defining helper or utility functions. An example would be the functions of collections in the Java standard library, that have a truly global scope. The same applies to constants. Read the discussion under this answer https://stackoverflow.com/a/48820895/1635488

In your case, DocPrefManager has a specific context. Also, I guess you don't want to pollute IDE auto-completion list with specific functions. It leads to unmaintainability.

P.S. DocPrefManager functions shouldn't depend on App.getContext(). DocPrefManager class should be initialized with a context and in that case using top-level functions is odd, cause your functions wouldn't be static.

android_dev
  • 3,886
  • 1
  • 33
  • 52
1

object Clazz will be compiled as singleton, top-level function will be compiled as static in JVM.

if there are no reasons for your method to be in instance, static(top-level, companion object) way would be a little bit high-performance.(ref: https://stackoverflow.com/a/11993118/5354658)

Choim
  • 372
  • 1
  • 10