How to force immediate instantiation of enum values?
By default, in Kotlin enums are instantiated on first access (like objects/singletons), i.e., the following minimal example
class Foo
fun create(msg: String) = Foo().also { println("$msg") }
enum class A(val foo: Foo) {
ONE(create("1")),
TWO(create("2"))
}
enum class B(val foo: Foo) {
THREE(create("3")),
FOUR(create("4"))
}
fun main() {
println("main")
println(A.ONE)
}
outputs:
main
1
2
ONE
Is it possible to force the enums to be instantiated directly/statically before main, such that the output is as follows?
1
2
3
4
main
ONE
Sure, I could just put something like val ignore = listOf(A.ONE, B.THREE) somewhere, but I'd like to avoid such manual repetition.
Maybe there's a way using some existing annotation, or creating a new one, or something else? :)
JVM loads classes only on first access. This is not only for kotlin but also for Java. For Java we have ways to initialize a class before main, for instance, static initializer block, or Class.forName. Similarly you can use the static initializer block in Kotlin.
object Temp {
init {
A.ONE
}
#JvmStatic fun main(args: Array<String>) {
println("main")
println(A.ONE)
}
}
Related
The following code is valid Kotlin code:
abstract class A {
protected lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
init {
v = f()
}
}
}
It defines an abstract class which has a lateinit var field and an abstract method that sets the value of that field. The reason behind this is that that method may be called later again, and its behavior should be defined in the subclasses that extend the original class.
This code is a simplification of a real-world code, and even though it works, I feel like it is messy since the developer of the subclass could choose not to (or forget) to call v = f() inside an init block. And we cannot do that in A either because then it will show a warning that we are calling a non-final method in the constructor. What I propose is the following:
abstract class A {
private lateinit var v: X
abstract fun f(): X
class SubA : A() {
override fun f(): X {
return SubX()
}
}
lateinit { // this does not exist
v = f()
}
}
The benefits of this is that now the field can be private instead of protected, and the developer does not have to manually call v = f() in each of their subclasses (or the subclasses of their subclasses), and the naming fits with the nomenclature of Kotlin since lateinit is already a keyword and init is already a block. The only difference between an init and a lateinit block would be that the contents of a lateinit block are executed after the subclass constructors, not before like init.
My question is, why isn't this a thing? Is this already possible with some other syntax that I do not know about? If not, do you think it's something that should be added to Kotlin? How and where can I make this suggestion so that the developers would most likely see it?
There are three options, and you can implement your lateinit block in two ways
don't lazy init - just have a normal construction parameter
use a delegated lazy property
add a lambda construction parameter to the superclass class A
All of these solves the problem of requiring subclasses of A having to perform some initialization task. The behaviour is encapsulated within class A.
Normal construction parameter
Normally I'd prefer this approach, and don't lazy init. It's usually not needed.
abstract class A(val v: X)
class SubA : A(SubX())
interface X
class SubX : X
fun f() can be replaced entirely by val v.
This has many advantages, primarily that it's easier to understand, manage because it's immutable, and update as your application changes.
Delegated lazy property
Assuming lazy initialization is required, and based on the example you've provided, I prefer the delegated lazy property approach.
The existing equivalent of your proposed lateinit block is a lazy property.
abstract class A {
protected val v: X by lazy { f() }
abstract fun f(): X
}
class SubA : A() {
override fun f(): X {
return SubX()
}
}
interface X
class SubX : X
The superclass can simply call the function f() from within the lazy {} block.
The lazy block will only run once, if it is required.
Construction parameter
Alternatively the superclass can define a lambda as construction parameter, which returns an X.
Using a lambda as a construction parameter might be preferred if the providers are independent of implementations of class A, so they can be defined separately, which helps with testing and re-used.
fun interface ValueProvider : () -> X
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X get() = valueProvider()
}
class SubA : A(ValueProvider { SubX() })
interface X
class SubX : X
The construction parameter replaces the need for fun f().
To make things crystal clear I've also defined the lambda as ValueProvider. This also makes it easier to find usages, and to define some KDoc on it.
For some variety, I haven't used a lazy delegate here. Because val v has a getter defined (get() = ...), valueProvider will always be invoked. But, if needed, a lazy property can be used again.
abstract class A(
private val valueProvider: ValueProvider
) {
protected val v: X by lazy(valueProvider)
}
In Kotlin, I want to add a "namespace" to a class that has a set of related functions. Clients of my class will use that namespace to help classify what type of operation they want to do. (I know you're thinking the functions should be in different classes, problem solved. But for other reasons, it's convenient to house all the functions in a single class).
So, I might have a class Uber that contains fooInsert fooOpen fooDispose along with barInsert barTerminate and barHop. As you can see there's no common interface. Just a bunch of functions that for some reason belong in the same class. Some have an affinity with others (i.e. the fooXXX functions "belong" together, as do the "barYYY" functions).
What I've come up with is:
class Uber {
inner class FooNamespace {
fun insert(): Unit {}
fun open(): Unit {}
fun dispose(): Unit {}
}
val foo = FooNamespace()
inner class BarNamespace {
fun insert(): Unit {}
fun terminate(): Unit {}
fun hop(): Unit {}
}
val bar = BarNamespace()
}
Users of the class can do something like this:
val uber = Uber()
uber.foo.insert()
uber.bar.hop()
What I'd like is something that combines the inner class ... and val xxx = XxxNamespace() into one expression. Something like:
// This doesn't actually compile
val foo = object: inner class {
fun insert(): Unit {}
fun open(): Unit {}
fun dispose(): Unit {}
}
The problem here is that you need a properly defined type if you to want to access these members publicly.
For private properties, the syntax val foo = object { ... } is sufficient, but for publicly exposed properties these are inferred as Any and it makes them unusable.
One option is obviously to define an interface for these types, but it's even more boilerplate than what you came up with already, so I am pretty sure this won't suit your needs:
interface FooNamespace {
fun insert()
fun open()
fun dispose()
}
class Uber {
val foo = object : FooNamespace {
override fun insert(): Unit {}
override fun open(): Unit {}
override fun dispose(): Unit {}
}
}
I know you're thinking the functions should be in different classes, problem solved. But for other reasons, it's convenient to house all of the functions in a single class
I'm indeed really thinking that, and would love to hear more about what makes it so convenient to put everything in the same class :) Since the classes are inner classes, I'm assuming this has to do with accessing private state from Uber, but that could also be done by wrapping this private state into another class that's passed to foo and bar.
I believe this is not possible, at least for now.
The main technical problem here is that uber.foo.insert() is really interpreted as chaining uber.foo and then .insert(). So for this to work, uber.foo needs to have an explicitly defined type. It can't be anonymous class/object, because then there is no way to describe what is the type of uber.foo.
That being said, I've always wondered why Kotlin does not support this syntax:
val foo = object Foo {}
This is consistent with the object declaration where the name of the singleton is at the same time the name of the class. And the compiler even understands this above syntax, because it throws the error: "An object expression cannot bind a name". So Kotlin authors seem to intentionally disallow such use.
I found an issue in the YouTrack, so we can at least upvote it: https://youtrack.jetbrains.com/issue/KT-21329
Could a class delegate an interface to multiple implementations with a few lines? Given this interface:
interface Foo {
fun doA()
fun doB()
}
The following class would compile for a single delegate:
class FooImpl(delegate: Foo): Foo by delegate
Although useless, it generates java bytecode for what is should do: delegate Foo -> Foo.
Could this be possible for a list of delegates as well? Such that it delegates Foo -> List<Foo>. Like:
class FooImpl(delegates: List<Foo>): Foo by delegates
Right now, our codebase is filled with classes such as:
class FooImpl(private val delegates: List<Foo>): Foo {
override fun doA() { delegates.forEach { it.doA() }
override fun doB() { delegates.forEach { it.doB() }
}
It feels like busy work and it's unnecessarily error prone, plus it creates unneeded work for the dev writing the code and the dev reviewing the code. I'm aware it can become complex for return values, but that will never be the case. In the current code, there's always a set of an interface, 2 actual implementations and a root implementation filled with doA() { delegates.forEach { it.doA() } .
Could this be simplified using Kotlin?
I'm trying to create a Map that contains generic-parameterized types. For example:
abstract class Foo {
companion object {
val fooInjectors = HashMap<Class<T: Foo>, Injector<T: Foo>>()
}
}
The idea is to have fooInjectors (which would be static in Java or in a companion object in Kotlin) contain a cache of sub-classes of Foo and their corresponding Injector.
Unfortunately, I can't get this to compile. I'd very much appreciate it if someone would help me figure out the syntax for this!
As far as I know, you are trying to do something that is impossible in Kotlin. The companion object is a singleton and it doesn't make sense to generify a singleton as there will not be any further objects created hence generic types are irrelevant. So you can't generify the property you declared because it's in the companion object.
However, one way you could make this working is using a backing function. This backing function should annotate with declaration-site variance.
This simply means we tell the compiler that we only return a type T from the method (and don't consume). That allows us to use subtypes and the supertype of the T if required. This is called covariance.
You can look at the docs to understand it further - https://kotlinlang.org/docs/reference/generics.html#declaration-site-variance
Here's what I meant.
interface Injector<T>
class InjectorImpl<T> : Injector<T>
abstract class Foo {
companion object {
val fooInjectors = createMap<Foo>()
private fun <T> createMap(): HashMap<Class<out T>, Injector<out T>> {
return HashMap()
}
}
}
class Bar: Foo()
object Runner {
#JvmStatic
fun main(args: Array<String>) {
Foo.fooInjectors[Bar::class.java] = InjectorImpl<Bar>()
Foo.fooInjectors[Foo::class.java] = InjectorImpl<Bar>()
}
}
A previous question shows how to put a static initializer inside a class using its companion object. I'm trying to find a way to add a static initializer at the package level, but it seems packages have no companion object.
// compiler error: Modifier 'companion' is not applicable inside 'file'
companion object { init { println("Loaded!") } }
fun main(args: Array<String>) { println("run!") }
I've tried other variations that might've made sense (init on its own, static), and I know as a workaround I can use a throwaway val as in
val static_init = {
println("ugly workaround")
}()
but is there a clean, official way to achieve the same result?
Edit: As #mfulton26's answer mentions, there is no such thing as a package-level function really in the JVM. Behind the scenes, the kotlin compiler is wrapping any free functions, including main in a class. I'm trying to add a static initializer to that class -- the class being generated by kotlin for the free functions declared in the file.
Currently there is no way to add code to the static constructor generated for Kotlin file classes, only top-level property initializers are getting there. This sounds like a feature request, so now there is an issue to track this: KT-13486 Package-level 'init' blocks
Another workaround is to place initialization in top-level private/internal object and reference that object in those functions that depend on the effect of that initialization. Objects are initialized lazily, when they are referenced first time.
fun dependsOnState(arg: Int) = State.run {
arg + value
}
private object State {
val value: Int
init {
value = 42
println("State was initialized")
}
}
As you mentioned, you need a property with something that would run on initialisation:
val x = run {
println("The package class has loaded")
}
I got around it by using a Backing Property on the top-level, under the Kotlin file. Kotlin Docs: Backing Properties
private var _table: Map<String, Int>? = null
public val table: Map<String, Int>
get() {
if (_table == null) {
_table = HashMap() // Type parameters are inferred
// .... some other initialising code here
}
return _table ?: throw AssertionError("Set to null by another thread")
}