Creating a singleton in kotlin (object/companion) ...
# getting-started
c
Creating a singleton in kotlin (object/companion) just for constants (like some INT codes my team uses in our files) seems wrong. What do people typically do? Just have top level constants? Or do people really just create companion objects?
v
For private constants I use top-level declaration. For non-private constants it depends on whether I want them in the namespace of a class or standalone in the package.
c
We want them in the namespace of the class so that it's
ErrorCodes.WARNING
for example.
v
Then there is no other choice than using a companion object, is there?
👆 1
n
it even makes sense as a companion object property (or
object
)
c
@Vampire I guess that's what I'm asking. It "feels" wrong/unidiomatic, but maybe it's the right choice. 😄
n
is
ErrorCodes
a real class, or just a bag of properties? could possibly also be an enum class
c
It's just a bag of Ints 😄
Copy code
object ErrorCodes {
const val SOME_ERROR = -1
const val SOME_WARNING = -2
...
}
n
yeah, I suspect your best bet will either be what you're already doing or an enum class
c
Thanks
a
@Colton Idle I would use an
enum class
, as you can use them in
when
expressions (and other things), and then they truly represent a type
ErrorCode
Constants like that are then really just “Ints” but you lose all the goodness of a better abstraction (the enum class), as an
object
used that way can’t enforce usage of the error code as any Int can be passed in to whatever you’re using these for. Also, when you use a when statement without an
else
, they must be exhaustive and you won’t miss an error.
Copy code
enum class ErrorCode(val number: Int) {
    SOME_ERROR(-1),
    SOME_WARNING(-2)
}

val error = ErrorCode.SOME_ERROR

fun handleError(error: ErrorCode): String =
  when(error) {
    ErrorCode.SOME_ERROR -> "Error" 
    ErrorCode.SOME_WARNING -> "Warning"
  }
👍 4
đŸ‘đŸ» 1
n
Also, when you use a when statement without an 
else
if used as an expression 🙂
c
a
@nanodeath Yeah, I suppose I haven’t run into that. I never use anything but expressions in Kotlin. if/when/try/etc. are all expressions in everything I’ve written in Kotlin since before 1.0. I do not like side-effects and I avoid
var
as much as possible, which is usually about 99.9% of the time (statistic made up, but just for a point and my example broke my rule for brevity hah.) IntelliJ warns about not being exhaustive when not using it as an expression so I missed that on my example, as I mentioned I tend to always use expressions, but it didn’t make sense for the example, but my example was a bad one. I’ll fix that.
@Colton Idle Interesting. I have a total aversion to annotations as they are opt-in (just Like java’s
@Nullable
). People will forget to use them if it’s not enforced by the compiler, so really hard to trust. In the case of that sealed class example, it means that everywhere that class hierarchy is used, the code must include that annotation to be consistent with its usage. So, again, you can’t trust that it’s being used consistently. _Side note_*:* Not to mention annotations are annoying baggage that forever follow your code. I do wish there had been a compiler flag to
--ignore-unresolved-annotations
, perhaps with an argument list (like someone using Spring persistence on their interfaces, where I want the interface but not the baggage spring might bring along). I wish annotations were “comments with flair”, like javadoc or something to bypass the compiler if need be.
t
@Alan B there's a @Retention(SOURCE) for annotations being a comment with flair.
v
Even with runtime retention they are not more than comments, are they? Unless someone evaluates and uses them.
a
@Tomasz Krakowiak Ahh yes, I see that the referenced
@Exhaustive
annotation used it. It’s just a gripe I have with runtime/binary annotations. 🙂 Let’s say, “aspect based” annotations are still baggage. If I want to reuse, let’s say an “entity” without hibernate, but its annotated to the hilt with hibernate or spring stuff, the code is not reusable, or you have to bring in all the dependencies that are there, even if it doesn’t ‘require’ you to enable them. Again, this is just an annoyance I have with them. It’s not “that big of a deal”. But, it’s something to take into consideration when designing a reusable, independent API/library. That’s all.