Is there a cleaner way to set a top-level variable later in code without making it a lateinit var? - variables

So what I want to achieve is that to have the top-level variable set some time later in the main function, but I don't want to make it a lateinit var which certainly breaks the Extension variable functionality.
For instance this code doesn't work since extension variables don't support lateinit modifier:
lateinit var Dispatchers.Konvironment: MainCoroutineDispatcher
private set
fun main() {
...
Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
So what I finally came up with is to use a dummy variable and implement the getter of the val variable.
val Dispatchers.Konvironment: MainCoroutineDispatcher
get() = dispatcher
private lateinit var dispatcher: MainCoroutineDispatcher
fun main() {
...
dispatcher = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
But it is certainly not clean way to do that. It looks ugly (ish) creating multiple variable in the top-level structure is not very clean architecture.
So is there any possible clean workarounds? Sort of like lazy initialization, by some delegates or something.

Well, partially answering your question:
var Dispatchers.Konvironment: MainCoroutineDispatcher
get() = dispatcher
private set(value) {
dispatcher = value
}
private lateinit var dispatcher: MainCoroutineDispatcher
fun main() {
...
Dispatchers.Konvironment = ArbitraryMainDispatcher(Thread.currentThread()) { queue.add(it) }
...
}
will give you the desired way of assigning the value. There is no way to get rid of this additional lazyinit variable, though.
Extensions are nothing more than just some Kotlin syntax sugar for static methods which take an instance of the extended class as one of the arguments, and perform some action. If you're familiar with Java then, for example, these extensions:
// Extensions.kt
fun Foo.extendedAction() {
println(this)
}
var Foo.extendedBar: Bar
get() = this.bar
set(value) {
this.bar = value
}
are under the hood these methods in Java:
public class ExtensionsKt {
public static final void extendedAction(Foo foo) {
System.out.println(foo);
}
public static final Bar getExtendedBar(Foo foo) {
return foo.getBar();
}
public static final Bar setExtendedBar(Foo foo, Bar bar) {
foo.setBar(bar);
}
}
The conclusion which maybe drawn from the above is that extensions don't actually add anything to the extended classes' signatures, they simply decorate them with additional functionality. Or, as put in the docs:
Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type.
So you can see, unless dispatcher somehow already exists within Dispatchers, you can't do what you want without providing an external, "backing" variable which value can be actually referenced by the extension.

Related

Possible to use Spring AOP (AspectJ) with Kotlin properties?

Is it possible to use Spring AOP (AspectJ) with Kotlin properties? Specifically due to how Kotlin compiles properties to Java:
a getter method, with the name calculated by prepending the get prefix
a setter method, with the name calculated by prepending the set prefix (only for var properties)
a private field, with the same name as the property name (only for properties with backing fields)
Consider the following minimal reproducible example:
#Retention(AnnotationRetention.RUNTIME)
#Target(AnnotationTarget.PROPERTY, AnnotationTarget.FUNCTION)
annotation class TestAnnotation
...
#Aspect
class TestAspect {
#Around("#annotation(annotation)")
fun throwingAround(joinPoint: ProceedingJoinPoint, annotation: TestAnnotation): Any? {
throw RuntimeException()
}
}
...
internal class MinimalReproducibleExample {
open class TestProperties {
#TestAnnotation
val sampleProperty: String = "sample property"
#TestAnnotation
fun sampleFunction(): String = "sample function"
}
private lateinit var testProperties: TestProperties
#BeforeEach
fun setUp() {
val aspectJProxyFactory = AspectJProxyFactory(TestProperties())
aspectJProxyFactory.addAspect(TestAspect())
val aopProxyFactory = DefaultAopProxyFactory()
val aopProxy = aopProxyFactory.createAopProxy(aspectJProxyFactory)
testProperties = aopProxy.proxy as TestProperties
}
#Test
fun test() {
println(testProperties.sampleProperty)
println(testProperties.sampleFunction())
}
}
Running the test yields:
null
sample function
When debugging I can see that the generated proxy is a cglib-backed proxy, which should be able to proxy to a concrete class, but it does not seem to invoke the configured aspect. Is there something wrong with my #Around definition, or is this a limitation of Kotlin properties and/or proxying concrete classes?
Was able to trigger the aspect above with the following changes:
Use a "site target" for the getter: #get:TestAnnotation
Make the property/function both open

Alternative way for kotlin static methods

Im kinda new to Kotlin and I was wondering how I could make a static method.
Test.foo() //I want to do this from somewhere else in the program
open class Test() {
private giorgor: String? = null
fun foo(value:String) {
giorgor = value
}
}
I need to change the value of giorgor from somewhere else in the code and I thought I could use a static method to do that but I dont know how. Test also needs to be an open class
The equivalent of a static method in Kotlin is a method in the companion object, e.g.:
class Test() {
// …
companion object {
fun foo() = // …
}
}
You can access it in the obvious way:
fun main() {
Test.foo()
}
However, the bits of code I've elided make me suspect that this isn't exactly what you want: your example has foo() referring to a property of Test — and because each instance of Test has its own version of that property, it would need to refer to an specific instance. (And if you had an instance, there would be no need of the companion class — you could just make it a regular method of Test.)
In a comment, you refer to a Minecraft plug-in — can you explain what requirements that has?
BTW, a simpler alternative to the companion object is just a top-level method:
fun foo() = // …
From the same file, you can call it as foo(); from elsewhere, you'd call it as <Filename>Kt.foo() (since the compiler generates a dummy classname for top-level functions and properties, based on the filename). However, the same issues apply to that too.
If I'm understanding you correctly, you want an object instead of a class
object Test {
var giorgor: String = "jiorgor"
fun foo() = println(giorgor)
}
fun main() {
Test.foo()
}
One way to do this is by making the class open or abstract and adding this
companion object Default: Test()
This makes it act like every method of Test() is inside the companion object Default.
If you wanted, you could also override an open method and make it have a different output for when it is used statically:
fun main() {
val test = Test()
test.foo() //Output: "jiorgor"
Test.foo() //Output: "static jiorgor"
}
public open class Test() {
var giorgor: String = "jiorgor"
open fun foo() = println(giorgor)
companion object Default : Test() {
override fun foo() = println("static jiorgor")
}
}

Simulate package-privacy on properties in Kotlin

So, I have an enum called Level. That enum is actually just a wrapper for some other Level. Now I need to access that wrapped value (currently a protected property) in a different class called Log which sits in the same package. Obviously I do not want to completely expose that property by making it internal or public, but I need to access that wrapped value in my Log class.
How to I do that?
As Kotlin doesn't provide anything similar to package-private visibility, everything I tried failed. I'm already aware of the possibility to put both classes in one file, but that only allows me to gain exclusive access to the classes themselves, not their properties. And because I need to have both classes public that won't help either. So if anyone knows a workaround, I would be more than happy to hear it, because even though I really like Kotlin, this might be the reason for me to drop the language.
Both classes I mentioned look as follows:
Level.kt
enum class Level(protected val level: java.util.logging.Level) {
/** Useful for stuff */
OFF(CustomLevel("OFF", Int.MAX_VALUE)),
ASSERT(CustomLevel("ASSERT", 1200)),
FATAL(CustomLevel("FATAL", 1100)),
ERROR(CustomLevel("ERROR", 1000)),
WARN(CustomLevel("WARN", 900)),
INFO(CustomLevel("INFO", 800)),
DEBUG(CustomLevel("DEBUG", 700)),
ALL(CustomLevel("ALL", Int.MIN_VALUE));
private class CustomLevel(name: String, value: Int) : java.util.logging.Level(name, value)
}
Log.kt
object Log {
private val DEFAULT_CONSOLE_VERBOSITY = Level.ERROR
private val DEFAULT_FILE_VERBOSITY = Level.ALL
#JvmStatic
var consoleVerbosity: Level
get() = Level.findLevel(consoleHandler.level)
set(value) {
consoleHandler.level = value.level // The property I need to access
}
#JvmStatic
var fileVerbosity: Level
get() = Level.findLevel(fileHandler.level)
set(value) {
fileHandler.level = value.level // The property I need to access
}
private val consoleHandler = ConsoleHandler()
init {
consoleHandler.formatter = SimpleFormatter()
consoleHandler.level = DEFAULT_CONSOLE_VERBOSITY.level
}
private val fileHandler = FileHandler()
init {
fileHandler.formatter = SimpleFormatter()
fileHandler.level = DEFAULT_FILE_VERBOSITY.level
}
}
I am running the latest stable version of Kotlin (1.4.31)
As a workaround you may define an extension function/property for Log class in the scope of Level class:
enum class Level(private val level: java.util.logging.Level) {
//...
//Option 1
companion object {
fun Log.getLevelOf(level: Level) = level.level
}
//Option 2
val Log._level get() = level
}
Also you may define extension property for Level class in the scope of Log class for more natural usage:
object Log {
//...
private val Level.level : java.util.logging.Level
get() = consoleHandler.level = Level.run { getLevelOf(this#level) } // For Option 1
get() = with(this) { _level } // For Option 2
}
Downside of this approach is a tough coupling between these classes.
You just have to use extension functions like this:
fun Level.toLevel() = this.level
That allows you to access protected properties of other classes.
You cannot access a private class from another class but you can access a class from a class that is packed inside a file. So the workaround is to make fun in public class to access the private class which is in the same file.
But the highlight is that you cannot write a class inside an enum class in Kotlin.
I still don't know how you managed to write this code down in an IDE, because it will show an error.

Infinite recursion in Getter in Kotlin

I am familiar with Java, but I am having difficulty working with Kotlin.
To illustrate my question, here is some Java Code. If the getter finds the field to be NULL, it initializes the field, before returning the field.
package test;
public class InitFieldJava {
private final static String SECRET = "secret";
private String mySecret;
public String getMySecret() {
if(mySecret == null) initMySecret();
return mySecret;
}
private void initMySecret() {
System.out.println("Initializing Secret ....");
mySecret = SECRET;
}
public static void main(String[] args) {
InitFieldJava field = new InitFieldJava();
System.out.println(field.getMySecret());
}
}
Can I do something like the above in Kotlin. My attempt in Kotlin looks like this:
package test
class InitFieldKotlin {
private val SECRET = "secret"
private var mySecret: String? = null
get() {
if (mySecret == null) initMySecret() //Infinite Recursion!!!
return mySecret
}
private fun initMySecret() {
println("Initializing Secret ....")
mySecret = SECRET
}
companion object {
#JvmStatic
fun main(args: Array<String>) {
val field = InitFieldKotlin()
println(field.mySecret)
}
}
}
My problem is that this results in infinite recursion:
Exception in thread "main" java.lang.StackOverflowError
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
at test.InitFieldKotlin.getMySecret(InitFieldKotlin.kt:7)
I’d appreciate knowing what I’m doing wrong.
Try to use field keyword inside get():
private var mySecret: String? = null
get() {
if (field == null) initMySecret()
return field
}
Generally speaking, field allows to access your value directly without calling get, almost in the same way as in your Java example. More information can be found in documentation.
The problem you're facing is that when you call your property this way, the getter will be called again. And when you call getter, another getter is called, and so on until an StackOverflow.
You can fix this as shown by #Google, and using field inside the getter, instead of the property name:
if (field == null)initMySecret()
This way you won't access the property using its getter.
But more importantly: why don't you use a lazy initialization? If the variable is final, and it seems to be, you could use a lazy val
This way, the field won't be nullable anymore, so you won't have to safe-call it. And you'll not use boilerplate code, Kotlin can do this lazy initialization for you!
val mySecret: String by lazy {
println("Initializing Secret. This print will be executed only once!")
"SECRETE" //This value will be returned on further calls
}
More examples on Lazy can be seen at Kotlin Docs

How to check if a "lateinit" variable has been initialized?

I wonder if there is a way to check if a lateinit variable has been initialized. For example:
class Foo() {
private lateinit var myFile: File
fun bar(path: String?) {
path?.let { myFile = File(it) }
}
fun bar2() {
myFile.whateverMethod()
// May crash since I don't know whether myFile has been initialized
}
}
There is a lateinit improvement in Kotlin 1.2 that allows to check the initialization state of lateinit variable directly:
lateinit var file: File
if (this::file.isInitialized) { ... }
See the annoucement on JetBrains blog or the KEEP proposal.
UPDATE: Kotlin 1.2 has been released. You can find lateinit enhancements here:
Checking whether a lateinit var is initialized
Lateinit top-level properties and local variables
Using .isInitialized property one can check initialization state of a lateinit variable.
if (::file.isInitialized) {
// File is initialized
} else {
// File is not initialized
}
You can easily do this by:
::variableName.isInitialized
or
this::variableName.isInitialized
But if you are inside a listener or inner class, do this:
this#OuterClassName::variableName.isInitialized
Note: The above statements work fine if you are writing them in the same file(same class or inner class) where the variable is declared but this will not work if you want to check the variable of other class (which could be a superclass or any other class which is instantiated), for ex:
class Test {
lateinit var str:String
}
And to check if str is initialized:
What we are doing here: checking isInitialized for field str of Test class in Test2 class.
And we get an error backing field of var is not accessible at this point.
Check a question already raised about this.
Try to use it and you will receive a UninitializedPropertyAccessException if it is not initialized.
lateinit is specifically for cases where fields are initialized after construction, but before actual use (a model which most injection frameworks use).
If this is not your use case lateinit might not be the right choice.
EDIT: Based on what you want to do something like this would work better:
val chosenFile = SimpleObjectProperty<File?>
val button: Button
// Disables the button if chosenFile.get() is null
button.disableProperty.bind(chosenFile.isNull())
If you have a lateinit property in one class and need to check if it is initialized from another class
if(foo::file.isInitialized) // this wouldn't work
The workaround I have found is to create a function to check if the property is initialized and then you can call that function from any other class.
Example:
class Foo() {
private lateinit var myFile: File
fun isFileInitialised() = ::file.isInitialized
}
// in another class
class Bar() {
val foo = Foo()
if(foo.isFileInitialised()) // this should work
}
This will work
if (::list.isInitialized) {
//true
}
else {
//false
}
Accepted answer gives me a compiler error in Kotlin 1.3+, I had to explicitly mention the this keyword before ::. Below is the working code.
lateinit var file: File
if (this::file.isInitialized) {
// file is not null
}
Checking lateinit var
To check whether a lateinit var was initialized or not, simply use an .isInitialized boolean on the property reference :: .
if (foo::bar.isInitialized) {
println(foo.bar)
}
Playground Kotlin's code may look like this:
fun main() {
var declarative = Declarative()
declarative.checkLateInit()
}
class Declarative {
lateinit var compose: String
fun checkLateInit() {
println(this::compose.isInitialized)
compose = "Jetpack Compose 1.2"
if (this::compose.isInitialized) {
println(this.compose)
}
}
}
// Result:
// false
// Jetpack Compose 1.2
This checking is only available for the properties that are accessible lexically, i.e. declared in the same type or in one of the outer types, or at top level in the same file.
kotlin.UninitializedPropertyAccessException: lateinit property clientKeypair has not been initialized
Bytecode says...blah blah..
public final static synthetic access$getClientKeypair$p(Lcom/takharsh/ecdh/MainActivity;)Ljava/security/KeyPair;
`L0
LINENUMBER 11 L0
ALOAD 0
GETFIELD com/takharsh/ecdh/MainActivity.clientKeypair : Ljava/security/KeyPair;
DUP
IFNONNULL L1
LDC "clientKeypair"
INVOKESTATIC kotlin/jvm/internal/Intrinsics.throwUninitializedPropertyAccessException (Ljava/lang/String;)V
L1
ARETURN
L2
LOCALVARIABLE $this Lcom/takharsh/ecdh/MainActivity; L0 L2 0
MAXSTACK = 2
MAXLOCALS = 1
Kotlin creates an extra local variable of same instance and check if it null or not, if null then throws 'throwUninitializedPropertyAccessException' else return the local object.
Above bytecode explained here
Solution
Since kotlin 1.2 it allows to check weather lateinit var has been initialized or not using .isInitialized