Using lateinit primitives wrappers - kotlin

I've got something like that:
#LocalServerPort
private lateinit var serverPort: Integer
And IDEA warns that java.lang.Integer should not be used, use kotlin.Int instead. But kotlin.Int cannot be used with a lateinit property. Is there a way to satisfy both restrictions?
Update: I'm compiling with -Werror, as I think every project should. Therefore, code becomes ridden with #Suppress("PLATFORM_CLASS_MAPPED_TO_KOTLIN") adding unnecessary garbage.

Yes there is, Delegates.
#LocalServerPort
private var serverPort by Delegates.notNull<Int>()
Delegates are computationally slightly more expensive than lateinit. I use lateinit where I can, otherwise I use the method above. The code above will present exactly the same as lateinit ie. no null check needed.

Related

Property must be initialised even though type is defined in Kotlin

I am not sure Stack overflow will like this question. I am learning Kotlin and trying to declare a basic variable without any class.
This is the simplest example.
I now understand why the compiler won't accept it, says it must be initialised. But if I put it inside the main function, then it works fine.
I saw this tutorial on W3Schools and it says you dont have to initialise the variable if you declare its type? Well I have and it still is forcing me to initialise it
https://www.w3schools.com/kotlin/kotlin_variables.php
It's a simple variable in a file no class:
/**
* Number types:
* This is the most important, and we should be able to go over it quick.
* We start from the smallest to the biggest
*/
var byteEg: Byte;
Even inside a class it doesn't work:
class Variables{
var byteEg: Byte;
}
When I try latentinit it gives an exception: 'lateinit' modifier is not allowed on properties of primitive types
What W3Schools fails to mention is that it only holds true for variables that are not top level. So inside functions like
fun someFunction() {
var byteEg: Byte
}
if you want to do it with top level declarations you can mark it as lateinit like
lateinit var byteEg: Byte
The general principle is that everything must be initialised before it's used.*
(This is in contrast to languages like C, in which uninitialised values hold random data that could be impossible, invalid, or cause an error if used; and languages like Java, which initialise everything to 0/false/null if you don't specify.)
That can happen in the declaration itself; and that's often the best place. But it's not the only option.
Local variables can be declared without an initialiser, as long as the compiler can confirm that they always get set before they're used. If not, you get a compilation error when you try to use it:
fun main() {
var byteEg: Byte
println(byteEg) // ← error ‘Variable 'byteEg' must be initialized’
}
Similarly, class properties can be declared without an initialiser, as long as a constructor or init block always sets them.
In your example, you could set byteEg in a constructor:
class Variables2 {
var byteEg: Byte
constructor(b: Byte) {
byteEg = b
}
}
Or in an init block:
class Variables {
var byteEg: Byte
init {
byteEg = 1.toByte()
}
}
But it has to be set at some point during class initialisation. (The compiler is a little stricter about properties, because of the risk of them being accessed by other threads — which doesn't apply to local variables.)
Note that this includes vals as well as vars, as long as the compiler can confirm that they always get set exactly once before they're used. (Kotlin calls this ‘deferred assignment’; in Java, it's called a ‘blank final’.)
As another answer mentions, there's an exception to this for lateinit variables, but those are a bit specialised: they can't hold primitive types such as Byte, nor nullable types such as String?, and have to be var even if the value never changes once set. They also have a small performance overhead (having to check for initialisation at each access) — and of course if you make a coding error you get an UninitializedPropertyAccessException at some point during runtime instead of a nice compile-time error. lateinit is very useful for a few specific cases, such as dependency injection, but I wouldn't recommend them for anything else.
(* In fact, there are rare corner cases that let you see a property before it's been properly initialised, involving constructors calling overridden methods or properties. (In Kotlin/JVM, you get to see Java's 0/false/null; I don't know about other platforms.) This is why it's usually recommended not to call any of a class's non-final methods or properties from its constructors or init blocks.)

Kotlin non nullable map allows remove null

Why this code can be compiled and executed without erros?
val map = HashMap<Int, Long>()
val key :Int? = null
map.remove(key)
In MutableMap remove declared as accepting only non nullable key, so it shouldn't even compile. Is it a Kotlin type inference bug or am I missing something?
public fun remove(key: K): V?
Your code is perfectly fine as remove() allows nullable arguments - your map contents definition got nothing to it. When remove() is invoked, it would try to find matching requested key in the map and as it's not there (it's completely irrelevant why it's not there - it's valid case for key to be not present) nothing will happen. Where compiler will complain is on any attempt to put such key into your map. Then map definition kicks in and since it's known that nullable keys not allowed, such code won't even compile as this is clearly buggy code.
In this case, map.remove(key) doesn't not calls
public fun remove(key: K): V?
It calls an extension remove function:
public inline fun <#OnlyInputTypes K, V> MutableMap<out K, V>.remove(key: K): V? =
#Suppress("UNCHECKED_CAST") (this as MutableMap<K, V>).remove(key)
This function documentation says that it allows to overcome type-safety restriction of remove that requires to pass a key of type K.
It allows overcoming type-safety restriction because the key of the entry you are removing does not have to be the same type as the object that you pass into remove(key); the specification of the method only requires that they be equal. This follows from how the equals() method takes in an Any as a parameter, not just the same type as the object.
Although it may be commonly true that many classes have equals() defined so that its objects can only be equal to objects of its own class, there are many places where this is not the case. For example, the specification for List.equals() says that two List objects are equal if they are both Lists and have the same contents, even if they are different implementations of List. So, for example, according to the specification of the method, it is possible to have a MutableMap<ArrayList<Something>, Something> and call remove(key) with a LinkedList as an argument, and it should retrieve the key which is a list with the same contents. This would not be possible if this extension remove(key) didn't exist.[1]
Kotlin could warn or refuse to compile (would be good), but it doesn't (for now).
The reason for it being not as bad as it looks from a first glance is that you cannot put an Int? into a MutableMap<Int, Long> because
val map = HashMap<Int, Long>()
val key :Int? = null
map.put(key, 1) // <--- WON'T COMPILE [Type mismatch: inferred type was Int? but Int was expected]
map.remove(key)
Nevertheless, I think you are right by wondering about that method being compiled.
Eventually asking this question helped to find another question with explanation. In short, what actually happens is call of the extension function which have it's own type inference.

Kotlin-allopen plugin + #JvmField on a val not final enough

I am testing a new kotlin-allopen and kotlin-spring plugins under Kotlin 1.0.6.
In one of my #Transactional-annotated classes I have a field:
#JvmField val foo = null
When I try to build the project, I get:
Error:(45, 5) Kotlin: JvmField can only be applied to final property
Is there any proper way of dealing with this? My real-life code needed #JvmField because of the JUnit's #Rule. Managed to "solve" the problem by removing a #JvmField and annotating a getter instead. Not sure if a bug or a feature.
I got the official solution.
In such case, finality provided by val is not enough. It turns out you need explicitly add final keyword there and this is not considered a bug.
#JvmField final val foo = null

Call java varargs method from kotlin

I have a java function:
public static void initialize(#NonNull Activity activity, Settings... settings) {}
I want to call it from kotlin:
fun initialize(activity: Activity, vararg settings: settings) = JavaClass.initialize(activity, settings)
But it does not compile, telling me that there is type mismatch, Settings is required, but the argument is kotlin.Array<out Settings>
I see that it's trying to match it with signture
public static void initialize(#NonNull Activity activity, Settings settings) {}
but I want to use
public static void initialize(#NonNull Activity activity, Settings[] settings) {}
You should use the following syntax:
fun initialize(activity: Activity, vararg settings: settings) =
JavaClass.initialize(activity, *settings)
https://kotlinlang.org/docs/reference/java-interop.html#java-varargs
Michael's answer is correct, though I'd like to make some additional comments.
The reason you cannot pass a Kotlin vararg parameter into a Java (or Kotlin) function that expects another vararg is because the compiler resolves the vararg into an Array.
Hence, it is as if you've declared your function as below (from the perspective of the function's internal scope):
fun initialize(activity: Activity, settings: Array<Settings>) = //...
This is why it is unintuitive that we need to use the spread * operator. As far as I can tell, there are two benefits to this design choice:
The spread operator, in addition to being used to populate variable arguments, can be used to mix-and-match between individual arguments and spreaded arrays. This means that Kotlin is giving us a convenient way to add additional parameters to a vararg list.
In Java, the following code does not compile:
Settings[] settings = //...
Setting myAdditionalSetting = new Setting();
JavaClass.initialize(activity, settings, myAdditionalSetting); //Compiler Error
However, in Kotlin we can do this:
JavaClass.initialize(activity, *settings, myAdditionalSetting)
The second benefit is increased safety. The spread operator compiles down to a call to Arrays.copyOf() which guarantees immutability of the spreaded values.i This ensures that the called function cannot corrupt the original array.
i: While the actual class references would be immutable, the objects they refer to might still be mutable.

Kotlin JUnit Rules

In Kotlin M13, this was an acceptable way to create a JUnit rule:
#Rule #publicField val temp = TemporaryFolder()
Now that #publicField has been deprecated, how else can this be achieved? The IDE hint suggests replacing #publicField with lateinit, but lateinit val's are no longer allowed, and I'm not sure this would help even if they were.
The answer as of Kotlin 1.0 is as follows:
#Rule #JvmField val temp = TemporaryFolder()
#JvmField exposes the backing field with the same visibility as the property, ergo a public field for the JUnit rule to use.
If anyone stumble's on this. I believe the approach with JJunit5 would be using #TempDir.
https://junit.org/junit5/docs/5.4.2/api/org/junit/jupiter/api/io/TempDir.html
If you would need share the TempDir with tests, it must be a static property of the class. Static for java or within a companion Object for Kotlin
Just guessing, but the following might work (with var):
#Rule lateinit var temp = TemporaryFolder()
I would try asking at kotlin's slack http://t.co/xpQXUKaDvP
Currently it's the fastest way to fix anything.