I’m often unsure if write some functions at top-level or in a singleton object.
As example, I’ve noted the function
generateSequence in stdlib is at top-level, but probably it could be declared as
Sequence.generate. So why have you preferred this?
Essentially they are equivalent, but there are some differences:
- top-level declarations are directly available from the code completion list, so they should be easier to find
- top-level names can clash easily with other declarations
- declarations at top-level are simplier since they don’t require to nest elements inside an object.
So in your opinion what are the best practices to choose top level declarations?
This is not by any means a full answer, but one thing to consider would be whether the function is independent of an object. Utility functions (think java.util.Math) should not belong in classes as there is nothing object oriented about them. Another case would be “factory” methods that have the name fo the type they create (from calling source code they are indistinguishable from a constructor call), but those functions need to be used judiciously.
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.
FWIW I love the way it works in Java. All utility methods may have multiple versions, even the methods in
Math have a buddy in
StrictMath (which nobody uses, but that’s a different story).
I myself use three different versions of my own
pow(long, long), namely checked (throwing on overflow), unchecked (ignoring overflow) and saturated. The best naming I could come up with was
SaturatedMath.pow (which is nicely short with a static import).
saturatedPow would only make sense if I needed to use multiple versions in one class, but I never do.
- Using multiple packages makes no sense as they’d contains just one file each.
The idiomatic Kotlin way to express that would be
import kotlin.math.saturated.pow. Since the Kotlin package structure doesn’t have to match directory structure, there is no issue with creating packages containing a single file - you don’t need to put each of these files into a separate directory.
Isn’t the Kotlin stdlib using
object namespacing with
Delegates? Also, recently, kotlinx.coroutines introduced
Dispatchers for easy dispatchers discovery.
Can you elaborate on why do you think using
object is bad for creating namespaces? I didn’t know it’s a recommended practice to avoid it. Is it mentioned anywhere else, e.g. Kotlin Coding Conventions?
During the years developing in Kotlin I moved through these steps:
- do it as close to java-style as possible, i.e. constants within objects
- do it the recommended kotlin way with top level declarations for all constants
- back to objects for non-private constants
In our project we have often cases in which a constant needs to be used in exactly 2 places (server / client). Such constants are easier to deal with in objects. Because they don’t pollute the IDE’s global code completion namespace.
Having said this, when using those constants in code I don’t prefix them with the object’s name. I use the object’s name just for discovery and code completion, and then I import the constant.
Because they don’t pollute the IDE’s global code completion namespace.
Don’t ‘top-level’ declarations go in the package’s namespace, not in a global one? (Unless they’re in the default package, of course.)
Yes, but in reality you never use the default package. When people say global namespace they normaly mean package namespace in both kotlin and java.
By this I mean the constants that can be code completed in the IDE without prefixing them with any name.