Is a val property thread-safety? - kotlin

I can use Code A to change the value of val a .
In my mind that val property is thread-safe, but it seems that it's not thread -safe in Code A,
it's just like var property, any thread can change the variable aImpl, different thread maybe get different value of val a
Code A
var aImpl = 0
val a: Int get() = aImpl
fun seta(){
aImpl=5
}

You fail to make a clear distinction between a val with and without a custom getter. If you lump those two together, like in your question, then val is not thread-safe; however Kotlin does make this distinction, as you can observe in this example:
val simpleVal: Int? = 3
val customVal: Int? get() = simpleVal
fun main(args: Array<String>) {
if (simpleVal != null) {
println(simpleVal + 1)
}
if (customVal != null) {
println(customVal + 1) // ERROR!
}
}
Error:(12, 21) Kotlin: Smart cast to 'Int' is impossible, because 'customVal' is a property that has open or custom getter
The smart cast is not allowed, among other reasons, due to the potential of another thread mutating the result of the custom get() call.
Therefore:
A simple val is thread-safe;
A val with a custom or open getter is not (necessarily) thread-safe.

Of course not. It will work as a dynamic getter for aImpl, not as property.
And aImpl isn't #Volatile, so there is no any guarantees of thread-safety.

Related

Calculated transient value is null after deserialisation with Gson

I run into an error which I do not understand after deserializing with gson.
My usecase is way more complex, but I created this test below which shows the behaviour I see.
The issue is the calculated transient value (allObjs) that is null after deserialisation. The unit test fails on the last assert.
Apparently the #Transient prevents correct initialisation of allObjs after deserialisation.
Is this expected behaviour? Can I do anything to make the field work in this way?
If not then I have to convert all the transient fields to functions like getThemAll(), which does work.
I hope for any insights.
Regards, Rob
class CoupleDeserializeTest {
data class Couple( val objA: String, val objB: String){
#Transient
val allObjs: List<String> = listOf(objA, objB)
fun getThemAll() = listOf(objA, objB)
}
#Test
fun testDe_SerializeCouple() {
val couple = Couple("my", "text")
// This succeeds
Assert.assertNotNull(couple.allObjs)
val gson = Gson()
val json = gson.toJson(couple)
// This succeeds
Assert.assertEquals("{\"objA\":\"my\",\"objB\":\"text\"}", json)
val coupleDeserialized = gson.fromJson<Couple>(json, Couple::class.java)
// This succeeds
Assert.assertNotNull(coupleDeserialized.getThemAll())
// This fails
Assert.assertNotNull(coupleDeserialized.allObjs)
}
}
If you are marking a field as Transient, it will ignore the field from serialisation or deserialisation, snippet from JvmFlagAnnotations
/**
* Marks the JVM backing field of the annotated property as `transient`, meaning that it is not
* part of the default serialized form of the object.
*/
#Target(FIELD)
#Retention(AnnotationRetention.SOURCE)
#MustBeDocumented
public actual annotation class Transient
EDIT
It will ignore it in initialisation because, the value of objA and objB will be initialised using serialisation meaning objA and objB have not assigned by the time you allObjs gets initialised, to get the values later instead of directly assigning, you can use get()
data class Couple( val objA: String, val objB: String){
#Transient
val allObjs: List<String>
get() = listOf(objA, objB)
fun getThemAll() = listOf(objA, objB)
}

Retrieve data class members

I need to check if any variables inside of my data class are null. To do this I need retrieve them first but I can't access them directly (e.g. myDataClass.name) because I need it to be generic. Is there a way to access these variables without directly naming them. For example, like accessing a member of an array (myArray[0]).
The mechanism you're looking for is called "reflection" and it allows to introspect objects at runtime. You'll find a lot of information on the internet, but just to give you a link you may want to check this answer.
In your case you could do something like this:
data class MyDataClass(
val first: String?,
val second: String?,
val third: Int?
)
fun main() {
val a = MyDataClass("firstValue", "secondValue", 1)
val b = MyDataClass("firstValue", null, null)
printProperties(a)
printProperties(b)
}
fun printProperties(target: MyDataClass) {
val properties = target::class.memberProperties
for (property in properties) {
val value = property.getter.call(target)
val propertyName = property.name
println("$propertyName=$value")
}
}
Note that for this code to work you must add kotlin-reflect package as a dependency.

Generic inline function

Let's say I have an object which helps me to deserialize other objects from storage:
val books: MutableList<Book> = deserializer.getBookList()
val persons: MutableList<Person> = deserializer.getPersonList()
The methods getBookList and getPersonList are extension functions I have written. Their logic is allmost the same so I thought I may can combine them into one method. My problem is the generic return type. The methods look like this:
fun DataInput.getBookList(): MutableList<Book> {
val list = mutableListOf<Book>()
val size = this.readInt()
for(i in 0 .. size) {
val item = Book()
item.readExternal(this)
list.add(item)
}
return list
}
Is there some Kotlin magic (maybe with inline functions) which I can use to detect the List type and generify this methods? I think the problem would be val item = T() which will not work for generic types, right? Or is this possible with inline functions?
You cannot call the constructor of a generic type, because the compiler can't guarantee that it has a constructor (the type could be from an interface). What you can do to get around this though, is to pass a "creator"-function as a parameter to your function. Like this:
fun <T> DataInput.getList(createT: () -> T): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
for(i in 0 .. size) {
val item = createT()
/* Unless readExternal is an extension on Any, this function
* either needs to be passed as a parameter as well,
* or you need add an upper bound to your type parameter
* with <T : SomeInterfaceWithReadExternal>
*/
item.readExternal(this)
list.add(item)
}
return list
}
Now you can call the function like this:
val books: MutableList<Book> = deserializer.getList(::Book)
val persons: MutableList<Person> = deserializer.getList(::Person)
Note:
As marstran mentioned in a comment, this requires the class to have a zero-arg constructor to work, or it will throw an exception at runtime. The compiler will not warn you if the constructor doesn't exist, so if you pick this way, make sure you actually pass a class with a zero-arg constructor.
You can't initialize generic types, in Kotlin or Java. At least not in the "traditional" way. You can't do this:
val item = T()
In Java, you'd pass a Class<T> and get the constructor. Very basic example of that:
public <T> void x(Class<T> cls){
cls.getConstructor().newInstance(); // Obviously you'd do something with the return value, but this is just a dummy example
}
You could do the same in Kotlin, but Kotlin has a reified keyword that makes it slightly easier. This requires an inline function, which means you'd change your function to:
inline fun <reified T> DataInput.getBookList(): MutableList<T> { // Notice the `<reified T>`
val list = mutableListOf<T>() // Use T here
val size = this.readInt()
for(i in 0 .. size) {
// This is where the initialization happens; you get the constructor, and create a new instance.
// Also works with arguments, if you have any, but you used an empty one so I assume yours is empty
val item = T::class.java.getConstructor().newInstance()!!
item.readExternal(this) // However, this is tricky. See my notes below this code block
list.add(item)
}
return list
}
However, readExternal isn't present in Any, which will present problems. The only exception is if you have an extension function for either Any or a generic type with that name and input.
If it's specific to some classes, then you can't do it like this, unless you have a shared parent. For an instance:
class Book(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
class Person(){
fun readExternal(input: DataInput) { /*Foo bar */}
}
Would not work. There's no shared parent except Any, and Any doesn't have readExternal. The method is manually defined in each of them.
You could create a shared parent, as an interface or abstract class (assuming there isn't one already), and use <reified T : TheSharedParent>, and you would have access to it.
You could of course use reflection, but it's slightly harder, and adds some exceptions you need to handle. I don't recommend doing this; I'd personally use a superclass.
inline fun <reified T> DataInput.getBookList(): MutableList<T> {
val list = mutableListOf<T>()
val size = this.readInt()
val method = try {
T::class.java.getMethod("readExternal", DataInput::class.java)
}catch(e: NoSuchMethodException){
throw RuntimeException()
}catch(e: SecurityException){
throw RuntimeException()// This could be done better; but error handling is up to you, so I'm just making a basic example
// The catch clauses are pretty self-explanatory; if something happens when trying to get the method itself,
// These two catch them
}
for(i in 0 .. size) {
val item: T = T::class.java.getConstructor().newInstance()!!
method.invoke(item, this)
list.add(item)
}
return list
}

Observable array in Kotlin to know when an array elt value is changed

My goal: I have a simple class with a public
val reds = IntArray(10)
val greens = IntArray(10)
val blues = IntArray(10)
val lums = IntArray(10)
If someone modifies any red value, I'd like to update the lum value.
myObj.reds[5] = 100 // Should update myObj.lums[5] = reds[5]+greens[5]+blues[5]
The problems is that the by Delegates.observable seem to only be used for var objects - nothing mentions "and if you modify an element of an array, here is what gets triggered"
Maybe this isn't possible and I have to do all modifications through getters and setters - but I'd much rather have something trigger like an observable!
You will have to use a custom class instead, IntArray is mapped to primitive int[] array so it doesn't provide any place to inject callback - changing value like your example (myObj.reds[5] = 100) you only know when array is returned, but have no control over changes after that.
For example you can create class like this:
class IntArrayWrapper(size: Int,
val setterObs : ((index: Int, value: Int) -> Unit)? = null){
val field = IntArray(size)
val size
get() = field.size
operator fun iterator() = field.iterator()
operator fun get(i: Int) : Int {
return field[i]
}
operator fun set(i: Int, value: Int){
field[i] = value
setterObs?.invoke(i, value)
}
}
Operator functions will let you get values from underlying array with same syntax as if you were accessing it directly. setterObs argument in constructor lets you pass the "observer" for setter method:
val reds = IntArrayWrapper(10){index, value ->
println("$index changed to $value")
invalidateLums(index) // method that modifies lums or whatever you need
}
val a = reds[2] // getter usage
reds[3] = 5 // setter usage that triggers the setter observer callback
reds.field[4] = 3 // set value in backing array directly, allows modification without setter callback
Note that this imposes limitations, as you won't be able to freely use IntArray extension methods without referencing backing field nor will you be able to pass this class as an Array argument.
I do not know if it is the cleanest way of solving your problem but, you could use the ObservableList (FX observable collections):
var numbers: ObservableList<Int> = FXCollections.observableArrayList()
numbers.addListener(ListChangeListener<Int> {
//Do things on change
})
But as I mentioned, by adding these collections you are mixing FX components into your application, which I do not know if it is wanted or even if it works on various platforms like android!

How to pass nullable type into function that takes a non null type?

Is this possible if I do a null check before passing? For example:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
if (num != null) doSomething(num)
}
fun doSomething(number: Int) {
...
}
I don't understand why the compiler won't allow me to pass a nullable even though I check that it's not null first. Can anyone explain?
NOTE: starting from compiler version 1.0 beta the code in question works as is
The compiler can tell if the variable is mutated between check and use, at least in case of local variables like in this question, and in some other cases. See Jayson's answer for details.
http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-keyword--in-conditions says
The compiler tracks the information about the [null] check ... this only works where b is immutable (i.e. a local val or a member val which has a backing field and is not overridable), because otherwise it might happen that b changes to null after the check.
So something like this should work:
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
fun doSomething(number: Int) {
...
}
Of course, it would be nicer to rewrite "stuff happens" in such a way that you could make num into a val in the first place.
In current Kotlin (1.0 beta or newer) you do not have this issue anymore. Your code would compile. A local variable that is val or var can safely Smart Cast since the compiler can determine if the value could have mutated or not (on another thread for example).
Here is an excerpt from another Stack Overflow question that covers more aspects of nullability and Kotlin's operators for dealing with them.
More about null Checking and Smart Casts
If you protect access to a nullable type with a null check, the compiler will smart cast the value within the body of the statement to be non nullable. There are some complicated flows where this cannot happen, but for common cases works fine.
val possibleXyz: Xyz? = ...
if (possibleXyz != null) {
// allowed to reference members:
possiblyXyz.foo()
// or also assign as non-nullable type:
val surelyXyz: Xyz = possibleXyz
}
Or if you do a is check for a non nullable type:
if (possibleXyz is Xyz) {
// allowed to reference members:
possiblyXyz.foo()
}
And the same for 'when' expressions that also safe cast:
when (possibleXyz) {
null -> doSomething()
else -> possibleXyz.foo()
}
// or
when (possibleXyz) {
is Xyz -> possibleXyz.foo()
is Alpha -> possibleXyz.dominate()
is Fish -> possibleXyz.swim()
}
Some things do not allow the null check to smart cast for the later use of the variable. The example above uses a local variable that in no way could have mutated in the flow of the application, whether val or var this variable had no opportunity to mutate into a null. But, in other cases where the compiler cannot guarantee the flow analysis, this would be an error:
var nullableInt: Int? = ...
public fun foo() {
if (nullableInt != null) {
// Error: "Smart cast to 'kotlin.Int' is impossible, because 'nullableInt' is a mutable property that could have been changed by this time"
val nonNullableInt: Int = nullableInt
}
}
The lifecycle of the variable nullableInt is not completely visible and may be assigned from other threads, the null check cannot be smart cast into a non nullable value. See the "Safe Calls" topic below for a workaround.
Another case that cannot be trusted by a smart cast to not mutate is a val property on an object that has a custom getter. In this case the compiler has no visibility into what mutates the value and therefore you will get an error message:
class MyThing {
val possibleXyz: Xyz?
get() { ... }
}
// now when referencing this class...
val thing = MyThing()
if (thing.possibleXyz != null) {
// error: "Kotlin: Smart cast to 'kotlin.Int' is impossible, because 'p.x' is a property that has open or custom getter"
thing.possiblyXyz.foo()
}
read more: Checking for null in conditions
You can use let to simplify the code. The kotlin scope function introduces a local variable in the context of "num". No need to declare temporary variable numVal.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
num?.let{
doSomething(it)
}
}
Which works same as below but simpler and cleaner.
fun main(args: Array<String>) {
var num: Int? = null
// Stuff happens that might make num not null
...
val numVal: Int? = num
if (numVal != null) doSomething(numVal)
}
Use can use Scoping function let or apply along with null safe operator ?.
fragmentManager?.let{
viewPager.adapter = TasksPagerAdapter(it)
}
This way you can pass a nullable type to a non-nullable type parameter