How do you namespace things in Kotlin?

I love Kotlin but I’m not quite sure how to properly separate concepts.

To give concrete examples:

  • Default enum value

    You refer to enum values like Enum.Value1, how do you get a default value? It’d make sense to have something like Enum.default, so I write:

    enum class Enum {
        Value1,
        Value2;
    
        companion object {
            val default = Value2
        }
    }
    

    This creates a whole new object that I don’t need and according to other discussions I shouldn’t be using objects for namespacing. The alternative would be a top-level EnumDefault I guess?

  • Factory methods

    Similarly, there are factory methods such as Url.fromString() that I either have to put into companion object or define at top level.

  • Global constants and variables

    It’s awesome when you can keep them private by sometimes you have various constants that just need to be public. And sometimes they are closely related. For instance, you could have BUTTON_ANIMATION_DURATION and BUTTON_ANIMATION_DELAY. It would be nice if you didn’t have to define it like that, instead, you might want to say something like

    object ButtonAnimation {
        const val DURATION = 250
        const val DELAY = 100
    }
    

    but then again, you created an object you don’t need, and unless you are using const accessing DURATION has to go through the whole accessing ButtonAnimation.INSTANCE and calling ButtonAnimation.getDURATION()

  • Nested classes

    In a similar way, you might want to have a file with classes such as Request and Response that are accesses as Handshake.Request and Handshake.Response from outside. You can somewhat solve this by putting them into another class, if it makes sense, or an interface.


It feels that it would be useful to allow importing packages. This would also help with conflicting import names. For instance, instead of writing

import library.widget.Preference as WidgetPreferenece
import myapp.config.Preference as ConfigPreference

you could write

import library.widget as widget
import myapp.config as config

val foo = findView<widget.Preference>()
val bar = config.Preference()

Also it would perhaps be nice to be able to write namespace ButtonAnimation {} or something like the following, that would be used solely for keeping constants, factory methods, etc together:

enum class Enum {
    Value1,
    Value2;

    companion namespace {     // not an object!
        val default = Value2
    }
}
1 Like

Always using top-level is a terrible alternative to using object for namespaces imo. If you have a large amount of top-level items things can get out of hand. Using objects for namespaces gives you structure.

It is a sore spot in Kotlin. There should be a namespace keyword, but in the mean time I would use the object keyword. Unless you’re using object to make thousands upon thousands of namespaces, the overhead from all the unnecessary objects being created is negligible.

But rather than a namespace keyword, if this is possible, it would be nice if the compiler could detect that your object is only being used as a namespace and not generate unnecessary objects under the hood.

1 Like

I’ve never found using objects for namespaces to create a problem. We use it quite heavily for typesafe dependency management.

I do think that the awkward the Op is seeing above is because of an unintentional misuse of the Enum itself. The Enum class is for detailing all possible values, things like default values are context-specific business logic in many systems, so for that reason we wouldn’t allow the above.

I recommend keeping business logic in specialised service classes, which aids testability.
Alternatively in Kotlin I believe you could look at using an Interface to declare a default enum

1 Like

unintentional misuse of the Enum itself

That depends on the Enum in question imo. I use Enums a lot for stuff like preference files or network protocols so I also keep factory methods inside them (e.g. Compression.fromString("zlib") Compression.Zlib) and so default values go there as well. Perhaps you can argue that this stuff should be elsewhere but I find this kind of organization much easier to read

1 Like

The possibility of adding a namespace keyword is on the radar:

2 Likes

If you have a look at the literature for the design of enums, in various languages, you’ll find clear patterns.
Nowhere in the Java documentation, or the Kotlin documentation, will you find examples of them being used for business logic like default values.

You can do it, but its not considered a good idea.

If using for any sort of configuration, when writing larger systems in Kotlin, I recommend adopting “DomainPreferences” classes, eg “EmailPreferences” to wrap groups of values, since they keep things like defaults and such in a single place, and they make it easy to test dependant services, since you can just feed them a POJO - what do we call POJOs in Kotlin anyway…?

@benwoodworth ah this would be great!

@wyaeld (This is a bit off-topic imo but–)

Here’s a more or less real class that’s a part of a handhshake code

enum class Compression(val string: String) {
    Off("off"),
    Zlib("zlib");

    companion object {
        val default = Off

        fun fromString(string: String) = Compression::string.find(string)
                ?: throw IllegalArgumentException("Bad compression method: '$string'")
    }
}

In my opinion it clearly describes the possible values, the possible string representation of those, what to do when the representation is missing and the way to convert it to a value.

If I have EmailPreferences then where do I put the default value for compression? Something like this?

object EmailPreferences {
    enum class Compression { ... }

    val defaultCompression = ...

    fun compressionFromString(...) = ...
}

Or something like this?

object EmailPreferences {
    object Compression {
        enum class Compression { ... }

        val default = ...

        fun fromString(...) = ...
    }
}

I find both of these awful

Nowhere in the Java documentation, or the Kotlin documentation, will you find examples of them being used for business logic like default values.

I don’t think I’ve seen examples of this in there but then I haven’t seen it elsewhere in the documentation either

I’ve put together a very contrived example, but its more to do with the fact that things like ‘defaults’ for use by a system, are often derived from something else.

https://gist.github.com/wyaeld/27eac0628c67528ac88d1b4437628e40

Depending on the frameworks, some of that info isn’t available until runtime, hence avoiding Objects. We build a lot of microservices on Ktor for example, and the Preference classes we build load the overall config, validate or default their particular domains, report any problems, convert values etc.

I see your point, but in your example defaultAlgorithm is not really “default” in the sense that CompressionPreferences can’t provide a non-default algorithm, nor it would make sense for it to provide one. So it should be just algorithm and of course you wouldn’t put it inside the enum.

Where you would use Compression.default would be something like

val compressionString = protocolMessage.getString("compression", null)
val compression = if (compressionString == null) {
    Compression.fromString(compressionString) 
} else {
    Compression.default
}

Or you could make it private and call Compression.fromStringOrNull(...)