Here is my kotlin class:
class Test{
val x: String = run {
y
}
val y: String = run {
x
}
}
The variables x and y both end up as null, despite being declared as non-nullable strings.
You can run it here. As you can see, you end up with null pointer exceptions from trying to call methods on x or y.
Why is this possible? How can you really have null safety with this in mind?
Well this is what your class decompiles to in Java:
public final class Test {
#NotNull
private final String x;
#NotNull
private final String y;
#NotNull
public final String getX() {
return this.x;
}
#NotNull
public final String getY() {
return this.y;
}
public Test() {
Test $this$run = (Test)this;
int var3 = false;
String var5 = $this$run.y;
this.x = var5;
$this$run = (Test)this;
var3 = false;
var5 = $this$run.x;
this.y = var5;
}
}
So your backing fields, x and y are declared first. They're not assigned a value yet so, in Java, that means their value is null because that's the default for an unassigned object reference.
After the getters, you have the constructor which is where the assignation is taking place. There are a few weird variables going around, but
Test $this$run = (Test)this;
is basically creating a variable that refers to this, the current object. And we can kinda reduce the assignment code down to
this.x = this.y // y is null, so x is set to null
this.y = this.x // x is null, so y is set to null
Because that default value for object references is null, whichever of your assignments runs first will always be reading a null value from the other variable (which, remember, you haven't explicitly assigned a value to yet).
Basically the order of initialisation matters in Kotlin, you can't refer to something that hasn't been declared yet. Like this won't work either:
class Thing {
val a = b
val b = "hi"
}
On the line where a is being assigned, the value of b is currently undefined. It won't run on the JVM either, because that code decompiles to basically this:
public final class Thing {
#NotNull
private final String a;
#NotNull
private final String b;
public Thing() {
this.a = this.b;
this.b = "hi";
}
}
and that this.a = this.b line will fail because "b may not have been initialised yet". You can get around that with the same trick in the decompiled version of your code, with the other variable assigned to this:
public Thing() {
Thing thing = (Thing) this;
this.a = thing.b;
this.b = "hi";
}
which will run, but a ends up assigned with the default value of null.
So basically, the code you're using is a tricky way to get around that kind of error and ultimately give you unexpected behaviour. Obviously your example is unrealistic (the results of a = b = a are inherently undefined), but it can happen with this kind of code too, where initialisation goes through other functions:
class Wow {
val a = doSomething()
val b = 1
fun doSomething() = b
}
In this case a ends up 0 on the JVM, the default value for an int, because when assigning a it basically goes on a detour through a function that reads b before that's been assigned its value. Kotlin (currently) doesn't seem to be capable of checking the validity of this kind of thing - so you'll run into problems trying to initialise things via functions sometimes:
class Wow {
// unassigned var
var a: Int
val b = 1
init {
// calls a function that assigns a value to a
doSomething()
}
fun doSomething() { a = 5 }
}
That will fail because it can't determine that a has been initialised, even though the init block does so, because it's happening as a side effect of another function. (And you could bury that assignment in any number of chained calls, which is probably why it's not a thing that's been "fixed" - if you start making guarantees about that kind of thing, it needs to be consistent!)
So basically, during initialisation you can do things which the compiler isn't able to catch, and that's how you can get around things like non-null guarantees. It doesn't come up often, but it's something to be aware of! And I'm only familiar with the JVM side, I'm assuming the undefined behaviour is platform-specific.
According to the Kotlin docs, "Data inconsistency with regard to initialization" can result in a NullPointerException.
Here are a couple links related to the topic:
https://kotlinlang.org/docs/null-safety.html#nullable-types-and-non-null-types
https://kotlinlang.org/docs/inheritance.html#derived-class-initialization-order
Edit: An example of a wrong answer! It's not circular: x is initialised to null because y is null at the time x is initialised (being uninitialised).
Well, it's circular. x is not null because y is not null which is not null because x is not null.
So it's not a valid program. Meaningful type inference can only be applied to valid programs.
Related
I'm wondering if it has something that works like static variable inside a function in C.
In C language we have this:
void next_x()
{
static int x = 0;
x++;
}
Variable x is declared and initialized inside a function. As far I know C - it can be used only in the scope of this function and it is initialized only in first call of this function.
I need something like this in Kotlin. I have code similar to this:
private val x: Int = 0
fun getNextX() : Int {
x++;
return x;
}
and I would like to have something like this:
fun getNextX() : Int {
static val x: Int = 0 // this is not Kotlin code
x++;
return x;
}
I want to:
Limit x variable scope to emphasize that this object is only used by this function and protect it from changes from outside
Initialize it only once
Keep value/state between function calls
Example above was simplified. In fact I need something like this for ArrayList with limited scope, but retaining state.
I realize that we have singleton pattern which is almost perfect for such needs (except limited scope), but maybe Kotlin offers something else?
There isn't anything similar to that in Kotlin, but to simulate a similar effect, you can declare an object with all your static variables as properties, and put the function body in an invoke operator:
object NextX {
private var x = 0
operator fun invoke() = x++
}
You basically create an object, but syntactically, it works like a function that you can call:
fun main() {
println(NextX()) // 0
println(NextX()) // 1
println(NextX()) // 2
}
If you think of the entire object as your function, then x is indeed only accessible within the "function".
Functions in Kotlin are stateless, so this is not possible out of the box.
You can get creative though, by having an object with a function which returns the function you desire.
val foo: () -> Int = object {
var x = 0
fun createFunc() = fun() = x++
}.createFunc()
foo() // 0
foo() // 1
Note how x doesn't even have to be private, because the object itself cannot be referenced.
This would meet your criteria.
I am aware that an argument passed to a function will be seen as "val", even if the variable was initialized as "var". But this has been a problem for me. In this example code below, I want to modify the value of variable "num" by using the function "changeNum". But of course, Kotlin won't allow me to modify it. How do I get around this? How can I use the function "changeNum" to modify the variable "num"?
fun main() {
var num: Int = 5
changeNum(num)
}
fun changeNum(num: Int){
num += 2
print(num)
}
Kotlin is pass-by-value, so you can't do that directly with primitive types like Int.
The usual approach is to just return a new value instead of modifying what you receive as argument (a functional approach). It makes it clearer from the calling code's perspective:
fun main() {
var num: Int = 5
num = changeNum(num)
}
fun changeNum(num: Int): Int {
val newValue = num + 2
print(newValue)
return newValue
}
If you really want to mutate the variable instead of returning a new value, here are 2 approaches I'm thinking of to do this:
put all the code operating on this value into a class, and make the local variable a property of that class (this is the OO approach)
put this primitive variable into a class, and pass an instance of that class
Option 1 would look like this:
class SomeClass(var num: Int) {
fun changeNum() {
num += 2
print(num)
}
}
fun main() {
val container = SomeClass(5)
container.changeNum()
}
Option 2 would look like this:
class SomeMutableContainer(var num: Int)
fun main() {
val container = SomeMutableContainer(5)
changeNum(container)
}
fun changeNum(container: SomeMutableContainer) {
container.num += 2
print(container.num)
}
It's possible to do this in Kotlin with a property
import kotlin.reflect.KMutableProperty0
var num = 1
fun main() {
println(num)
changeNum(::num)
println(num)
}
fun changeNum(numProperty: KMutableProperty0<Int>) {
numProperty.set(12345)
}
>> 1
>> 12345
A KMutableProperty0 represents a basic var, so you can pass in a property reference using the ::num syntax (same as how you'd pass a function reference). That way, instead of passing the current value, you're providing the function with a reference to the property itself, and then you can call set on it.
But the question is, do you really want to do this? Or are you overcomplicating something that should be done in a more simple way, or a more readable one? You can't actually do this with a variable, like you're trying to do inside fun main(), only properties on an object (top-level vars, basically) - but even if you could, why wouldn't you just do this instead?
fun main() {
var num: Int = 5
...
num = changeNum(num) // this would need renaming but y'know
}
it's still a one-line call, your changeNum function can still have side effects, do validation etc, it just returns the result instead of setting it as a side effect. This is a lot easier to follow, especially when it's the usual way of setting a value on a thing.
If you really want to use references, but making them top-level in your class is messy, then maybe consider creating a state object instead:
import kotlin.reflect.KMutableProperty0
data class AllThemNums(var num1 :Int = 1, var num2: Int = 9999)
fun main() {
val nums = AllThemNums(num1 = 5)
changeNum(nums::num1)
println(nums)
}
fun changeNum(numProperty: KMutableProperty0<Int>) {
numProperty.set(numProperty.get() + 2)
}
>> AllThemNums(num1=7, num2=9999)
you could even put the changeNum function inside the data class!
Im my project, I've defined a generic type for enclosing all scalar types, both primitives and user-defined.
data class pTp<T>(var v: T)
So I can create
fun PercAcumNorm(percAcum:pTp<Double>, perc:pTp<Double>,
valor:Double, Soma:Double)
{
perc.v = valor/soma
parcAcum.v += perc.v
}
Then one just needs to call
....
var pAcum:pTp<Double> = pTp(0.40)
var p = 0
var valor = 5
var soma = 100
percCalc(pAcum, p, soma, valor)
println(pAcum.v) // it prints 0.45
It's not the cleanest solution, but it's what can be done without using Kotlin's built-in features, which may be modified in the future.
I have read that using !! should generally be avoided.
Is there a way to write the following code in a more elegant way without having to add something like obsolete null checks and duplicated or dead blocks of code?
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
return field!!
}
}
Also I don't understand why the compiler requires the !!-'pray-this-isn't-null-operator' to be satisfied in this scenario.
EDIT: Consider that it is important to me that a potential solution uses lazy initialization if the field is null!
Problem
As Enzokie already mentioned in the comments, another thread could have changed field after the null check. The compiler has no way of knowing that, so you have to tell it.
class A(var field: Thing?) {
fun getField(): Thing {
if (field == null) {
field = Thing()
}
// another thread could have assigned null to field
return field!! // tell the compiler: I am sure that did not happen
}
}
Solution (Eager)
In you particular case it would be a good idea to use a parameter f (you could name it "field" too, but I avoided that for clarity) in the constructor (without val/var) and afterwards assign it to a property field to which you assign either f or a new instance of Thing.
This can be expressed really concise with the Elvis operator :? which takes the left hand side if not null and the right hand side of the expression otherwise. So, in the end field will be of type Thing.
class A(f: Thing?) {
val field = f ?: Thing() // inferred type Thing
}
Solution (Lazy)
Since it was mentioned by gidds, if you need to initialize field lazyly you could do it like this using delegated properties:
class A(f: Thing?) {
val field by lazy {
f ?: Thing() // inferred type Thing
}
}
The call site does not change:
val a = A(null) // field won't be initialized after this line...
a.field // ... but after this
How about this?
class A(field: Thing?) {
private lateinit var field: Thing
init {
field?.let { this.field = it }
}
fun getField(): Thing {
if (!this::field.isInitialized) {
field = Thing()
}
return field
}
}
When you define a field, you actually define a variable plus two accessor methods:
val counter: Integer = 0
It is possible to customize the accessor methods by writing this instead:
val n = 0
val counter: Integer
get() = n++
This will execute the n++ each time you access the counter field, which therefore returns different values on each access. It is uncommon and unexpected but technically possible.
Therefore the Kotlin compiler cannot assume that two accesses to the same field return the same value twice. Usually they do, but it is not guaranteed.
To work around this, you can read the field once by copying it into a local variable:
fun count() {
val counter = counter
println("The counter is $counter, and it is still $counter.")
}
I am trying to create a swap function which takes in two parameters as shown below:
fun swap(a :Int, b:Int) {
}
I call it like this:
var a = 10
var b = 5
swap(a,b)
// a should be 5
// b should be 10
The problem is that even if I swap the values inside the swap function it won't be reflected on the caller's side because it is passed as a copy and not as a reference.
Is there anyway to pass value types to swap function and allow the function the ability to change them.
There is absolutely no way to do it directly. Kotlin copies a value for scalar types (Double, Float, Boolean, Int, etc.). So any internal changes are lost.
For any other type, Kotlin copy a reference of parameter passed to the function. So any property/field alteration of parameter, also changes the caller parameter.
There is no way to change this behaviour.
After trying many ways to overcome the impossibility of passing scalar by reference, as happens in Kotlin, Java and some other languages; my current strategy is using for any scalar type a plain and generic wrap, as an above comment suggest.
Recently, I'm using this trick for everything, including inside a function that otherwise would demand that I return multiple values. The alternative is joining the returns in a artificial class or destructuring declarations: val (a, b, c) = function-call() syntax. However, I hate articial classes and destructuring declaration is for local variables only, and it's annoying when some needs visibility out of current block of commands.
My code is very simple:
data class p<T>( // It's a generic wrap class for scalar type T
var v:T
)
fun <T>swap(a:p<T>, b:p<T>){ // It's a generic swap for scalar types
var aux:p<T> = a.copy()
a.v = b.v
b.v =aux.v
}
fun main() {
var a:p<Int> = p<Int>(2) // 'a' is a kind of 'Int' variable
var b:p<Int> = p<Int>(3) // and so is 'b'
swap(a,b) // Exchange 'a' and 'b' values
println(a.v) // 3
println(b.v) // 2
}
The only drawback is not being able to use syntax sugar of a real scalar type.
I am forced to add .v on any use of a scalar variable.
I only uses that for variables that I need pass by reference in some function and it's not so common. I try, when possible, avoid collateral effects.
You can have a function that gets the references of variables
var x = 10
var y = 20
fun main() {
println("x=$x, y=$y") // x=10, y=20
swap(::x, ::y)
println("x=$x, y=$y") // x=20, y=10
}
fun <T> swap(firstRef: KMutableProperty0<T>, secRef: KMutableProperty0<T>) {
val temp = firstRef.get()
firstRef.set(secRef.get())
secRef.set(temp)
}
and you can pass the references of properties of some class like this swap(someClass::x, someClass::y)
the only limitation is that you can't pass references of local variables which is not the end of the world.
if you don't like the messy syntax you can always define a typealias and make it pretty:
typealias Ref<T> = KMutableProperty0<T>
fun <T> swap(firstRef: Ref<T>, secRef: Ref<T>) {
...
}
I know that OP didnĀ“t ask for this, but idiomatic Kotlin would look like:
var a = 1
var b = 2
a = b.also { b = a }
Seems like Kotlin behaves pretty much like Java does:
Is Kotlin "pass-by-value" or "pass-by-reference"?
simple way to swap is make support class
private fun swap(pair: Pair) {
pair.a += pair.b
pair.b = pair.a - pair.b
pair.a = pair.a - pair.b
}
private data class Pair(var a: Int, var b: Int)
fun main() {
val pair = Pair(10, 5)
swap(pair)
println(pair)
}
Initially I wanted to achieve
class NotationDiceRoll(notation: String) {
val rolls: Int
val sides: Int
init {
parseNotation(notation)
}
private fun parseNotation(notation: String) {
rolls = 1
sides = 4
}
}
But Kotlin complains that "Val cannot be reassigned".
It seems that the only place where the vals can be assigned is the init block. Alright then, it is more obvious after all. So I changed it to
class NotationDiceRoll(notation: String) {
val rolls: Int
val sides: Int
init {
(rolls, sides) = parseNotation(notation)
}
private fun parseNotation(notation: String): Pair<Int, Int> {
return Pair(1, 4)
}
}
Now Kotlin complains that "Variable 'rolls' must be initialized".
It can be solved by
init {
val(rolls, sides) = parseNotation(notation)
this.rolls = rolls
this.sides = sides
}
but it is less elegant.
So my question is: is the destructuring really possible only with the vals being declared on the same line?
This feature is called a destructuring declaration, and that's what it is, a declaration of new variables with immediate assignment to them. It's not just that variables declared with val can't be used in later destructuring, no variables declared earlier can. For example, the following doesn't work either:
var x = 0
var y = 0
(x, y) = Pair(1, 2)
It's worth noting though that the feature you're looking for (destructuring assignments) was one of the possible future features for Kotlin out of the 20 cards that were available to be voted on at the Kotlin 1.1 event. While the online survey is no longer up, you can see the description of the feature on this image, it's card number 15. It's a bit hard to make out, so here's what's on it:
15 Destructuring assignments
Kotlin already has destructuring declarations:
val (name, address) = findPerson(...)
Some users request destructuring assignments,
ie. assign to multiple previously declared var's:
var name = ...
...
var address = ...
...
(name, address) = findPerson(...)
Do you need this feature?
Update: here's an official doc with the proposed features, and here's the survey results.