New to Kotlin..having issues with Optionals and Casting - kotlin

Just ver confused about casting and how to set up class variables. In java it was possible to do
private var mSectionsStatePageAdapter : SectionsStatePagerAdapter? = null
private val mViewPager : ViewPager? = null
now we're in kotlin
class MainActivity : AppCompatActivity() {
private var mSectionsStatePageAdapter : SectionsStatePagerAdapter? = null
private val mViewPager : ViewPager? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
val mytoolbar:Toolbar = findViewById(R.id.top_toolbar)
setSupportActionBar(mytoolbar)
mSectionsStatePageAdapter = SectionsStatePagerAdapter(getSupportFragmentManager())
mViewPager = findViewById(R.id.viewpager1)
setupViewPager(mViewPager)
}
fun setupViewPager(viewPager :ViewPager):Unit {
var adapter : SectionsStatePagerAdapter = SectionsStatePagerAdapter(getSupportFragmentManager())
adapter.addFragment(Fragment1(),"Fragment1")
viewPager.setAdapter(adapter)
}
I'm getting val can't be reassigned...
Error:(65, 24) Smart cast to 'ViewPager!' is impossible, because 'mViewPager' is a mutable property that could have been changed by this time

For Android, it is common to use lateinit var because you create the object outside of constructor (in onCreate, etc). You can go with two route:
lateinit var variable:Type
var variable:Type?
I would recommend if your variable should be available when you are ready to use it. You do not need to do null check. lateinit mean late initialization. Kotlin use null to represent not yet initialized, so you cannot use nullable type and assign null on it.
If your variable is nullable, then you should go the second way.
Beside, if you are handling views, you should use Android extension to do it. You don't need to findViewById in Activity or Fragment yourself.

There are two things happening here.
First, as #gyosida points out, you have defined your mPager property as val instead of var so it cannot be reassigned in the line mViewPager = findViewById(R.id.viewpager1). As #Joshua points out, you either have to make it a var or you need to make it a lateinit val to solve the problem of it not being initialised with the class instance.
The second is represented by the actual error you describe of, 'mutable property that could have been changed', and you will continue to see this if you make it a var. The approach of using lateinit is most likely the better idea.
However, to explain this error, in your method declaration of:
fun setupViewPager(viewPager: ViewPager): Unit {
you have said that the argument for viewPager cannot be null. If it were, it would be viewPager: ViewPager?. So, if you pass something that could be null into it, you will get a compile error.
What Kotlin is telling you is that in between the lines:
mViewPager = findViewById(R.id.viewpager1)
and
setupViewPager(mViewPager)
something - imagine another method on another thread - could potentially have changed the value of mViewPager from that assigned instance to null. Therefore it's not safe to pass it in.
The only way to solve this without changing the method is supply a value that is guaranteed to be non-null. There are a few ways you could do that:
assign your value to a method-level variable that can't be interfered with, and supply that as the argument
only call your function if the value is non-null, e.g. mViewPager?.let{ pager -> setupViewPager(pager)}
assert that mViewPager will not be null, leaving any violations to fail at runtime, e.g. setupViewPager(mViewPager!!)

Related

Why do we need word get in String

My expectation:
I want to see something like that:
package com.example.myapplication
class ExampleGet {
val p2: String = "Black"
}
fun main(){
var ex = ExampleGet()
println(ex.p2)
}
I understand this example, it's work fine.
My problem
I don't know why do we need a word get in this class
package com.example.myapplication
class ExampleGet {
val p: String get() = "Black"
val p2: String = "Black"
}
fun main(){
var ex = ExampleGet()
println(ex.p)
println(ex.p2)
println(ex.p==ex.p2)
}
But I don't know what's difference between
Line 1
val p: String get() = "Black"
and
Line 2
val p2: String = "Black"
If we don't have any difference between Line 1 and Line 2 why do get() exist in kotlin? I ask because I have fond an example
package com.example.myapplication
import androidx.fragment.app.Fragment
import com.example.myapplication.databinding.FragmentThirdBinding
class ThirdFragment:Fragment() {
private var _binding : FragmentThirdBinding? = null
private val binding get() = _binding!!
}
I don't know why did people use
private val binding get() = _binding!!
but not
private val binding = _binding!!
Properties in Kotlin can have an initializer, a getter, and a setter, but all of them are optional.
When you write
val p2: String = "black"
the property p2 is initialized with value "black". It has an implicit getter that always returns the current value of the property, and it would have an implicit setter that sets that value, if it was a var and not a val.
When you write
val p: String get() = "black"
you defined an explicit getter for the property p that always returns "black". So, in this example it does not become clear what the difference is, because "black" is a constant value.
Let's consider instead the following example:
val p1 : String = System.nanoTime()
val p2 : String get() = System.nanoTime()
When you use property p1, it will always return the time in nanoseconds of the moment it was initialized.
However, when you use property p2, it will always return the time in nanoseconds of the moment, you are calling p2.
So, regarding your example with the property binding, the definition with getter instead of an initializer, allows to always get the value of the internal variable _binding instead of only its initial value. The variable _binding is called a backing property.
Short answer: both lines define a property, but one has an initialiser while the other overrides the getter method.
In Kotlin, a property always has a getter method (and, if it's mutable, a setter method). When you refer to the property (e.g. myExampleGet.p), you're actually calling the getter method. (This is unlike Java.) A property will usually (though not always) have a private field to store the value, as well (known as the ‘backing field’).
Let's take your two cases in reverse order. Your second case has an initialiser, which is the most common form:
val p2: String = "Black"
This defines a property called p2, of type String, and assigns it the initial value "Black". You don't specify a setter method, so you get the default one, which just returns the backing field.
Your first case provides a setter method, instead of an initialiser:
val p: String get() = "Black"
This says that p is a property with type String, and that its getter method always returns the hard-coded value "Black".
This property doesn't need a backing field, because it would never be used.
So, what's the difference? In your example, very little. The main one is that every instance of ExampleGet has a field called p2, all of which contain the same reference (to the hard-coded string); they do not have a field p. So p is more memory-efficient.
However, in other situations, the difference is much less subtle! For example, the setter might not return a constant value, e.g.:
class ExampleGet {
val p: String get() = (++counter).toString()
val p2: String = (++counter).toString()
private var counter = 0
}
Here p2 would always have the same value it was initialised with (probably "1"), while p would give a different value each time: "2", then "3", then "4", and so on. (In practice, such a getter might perform some calculation on another property, or get it from some other source, but I hope this illustrates the point.)
Another situation making the difference obvious would be if the properties were mutable, i.e. var instead of val:
class ExampleGet {
var p: String get() = "Black"
var p2: String = "Black"
}
Here p2 would behave as you expect, returning the value you set:
val eg = ExampleGet()
println(eg.p2) // prints "Black"
eg.p2 = "White"
println(eg.p2) // prints "White"
But p would always return the same value:
eg.p = "White"
println(eg.p) // prints "Black"
(I think p would have a backing field in this case, which would store whatever value you set — but you'd never be able to see that value, because the setter would always return the hard-coded value.)
So the two cases are doing very different things, even though the effect is practically the same in the code in the question.
The difference you can see in decompiled Kotlin into Java code
So the code:
class ExampleGet {
val p: String get() = "Black"
val p2: String = "Black"
}
Become (Java):
public final class ExampleGet {
#NotNull
private final String p2 = "Black";
#NotNull
public final String getP() {
return "Black";
}
#NotNull
public final String getP2() {
return this.p2;
}
}
As you can see, val with get() become method returning value.
In my practice, I use variable shadowing to make user's code operate with different type, for example:
val publicValue: List<String>
get() = _privateValue
private val _privateValue: MutableList<String>...
It's been covered, but specifically for this stuff in your example:
private var _binding : FragmentThirdBinding? = null
private val binding: FragmentThirdBinding get() = _binding!!
I've been explicit about the types here - _binding is nullable, binding is non-null. binding is a getter that's casting the value of _binding to another type (the non-null equivalent). When people access binding, they "don't have to worry" about it being null, don't have to do any null handling etc.
Here's the thing - none of that makes any sense. It's only non-null because they've asserted that with the !! operator (which should generally be seen as a red flag - it's circumventing the nullability checker, telling it it's wrong).
What they're probably doing is assigning binding later (e.g. in onCreate), but the variable needs to be initialised to something before that, so they make it nullable and set it to null as a placeholder. But that makes binding nullable, and it needs to be null-checked every time, even if in reality, it will always have been assigned to something by then, and will never be null when something tries to use it.
So this solution creates another placeholder variable, called _binding, which is nullable. But the code accesses binding instead, which is non-null. It's all based on the idea that _binding definitely won't be null when accessed, so the !! will always be valid.
This situation is what lateinit is for though:
lateinit var binding: FragmentThirdBinding
Same thing - a promise to assign it before it's read, no need for nullability. It's a var instead of a val but that's rarely going to matter, and not for something like this where you're only going to set it once anyway. To me it's more readable, uses the language features instead of working around them (!!), etc.
I'm not sure where the "cast a nullable field" pattern came from, it looks a lot like the way you're recommended to expose a private MutableLiveData as a public immutable LiveData type instead, so I'm not sure if people are just adapting that. Maybe there's a benefit to it I don't know about!

Is this correct "lateinit var text : String?"?

I need to know if this line code is right, my teacher told me it's correct, but I disagree 'cause "lateinit" can't be with a variable that could be null or not.
Line code:
lateinit var text : String?
Code:
val cadena = null
lateinit var text : String?
text = null
text = cadena ?: "Hola"
text?.let { println(text) }
You are correct and your teacher is wrong. Proof: lateinit var text : String? results in compilation error with Kotlin 1.3.50:
'lateinit' modifier is not allowed on properties of nullable types
How any teacher can possibly claim such code is correct is beyond me...
I would like to add a little deep dive into lateinit properties in Kotlin.
'lateinit' modifier is not allowed on properties of nullable type - this can be found in Kotlin documentation. This kind of modifier is for special kind of constructions. It's for fields that will be initialized somewhen after object creation. For example, via DI framework or mocking framework.
But, what is under that field? If we would check it, we will simply find that before initialization property has null value. Nothing more, nothing less, just null. But, if we would like to access that property before initialization UninitializedPropertyAccessException is thrown.
In Kotlin 1.3 lateinit properties got new property - isInitialized (to use it: ::lateinitiProperty.isInitilized). So, before we access that property we are able to check if under that field is null or something else, without throwing exception.
But, lateinit means that object will be initialized later as not null property. And a programmer guarantee that this value is not null after intialization. If it could be, why just not use nullable type?
If there is a way to uninialize lateinit property? Yes, it is. Via reflection we can set that value to null again (JVM is not null-safe). And accessing that field will not finish with NPE execption, but with UninitializedPropertyAccessException. And .isInitialized will return false for field that refers to null.
And how does it work?
class MyClass {
lateinit var lateinitObject: Any
fun test() {
println("Is initialized: ${::lateinitObject.isInitialized}") // false
lateinitObject = Unit
println("Is initialized: ${::lateinitObject.isInitialized}") // true
resetField(this, "lateinitObject")
println("Is initialized: ${::lateinitObject.isInitialized}") // false again
lateinitObject // this will throw UninitializedPropertyAccessException
}
}
fun resetField(target: Any, fieldName: String) {
val field = target.javaClass.getDeclaredField(fieldName)
with (field) {
isAccessible = true
set(target, null)
}
}
Ofc, using lateinit that way is probably not what you want, and treat is as a curio about lateinit design in JVM.
And due to your teacher - he wasn't right. Even if lateinit may refer to null (and it does actually), you cannot declare it as a nullable type. If you need to, you don't need lateinit modifier.

How to uninitialize lateinit in Kotlin

I have a lateinit var as
lateinit var someVariable: SomeVariable
I initialize this value like someVariable = SomeVariable() and use it whenever I need.
At a certain point, I want to set everything to default and want to "uninitialize" someVariable. How can I do that?
I am not looking for changing its type to a nullable object and set null. I need to keep it a Non-Null type.
I don't think it's possible without some kind of wrapper (or reflection, but about it in a moment).
In fact, lateinit is design for compatibility with DI frameworks etc. If you know the value can be uninitialized in any moment then you should use nullable type.
So, what about that reflection thing? lateinit is in fact a kind of smart wrapper that makes nullable value to act like not nullable, and instead of throwing NullPointerException throws UninitializedPropertyAccessException. lateinit property at the moment of declaration in JVM is null, so, let's make it null again ;)
So...
class MyClass {
lateinit var lateinitObject: Any
fun test() {
println("Is initialized: ${::lateinitObject.isInitialized}") // false
lateinitObject = Unit
println("Is initialized: ${::lateinitObject.isInitialized}") // true
resetField(this, "lateinitObject")
println("Is initialized: ${::lateinitObject.isInitialized}") // false
lateinitObject // this will throw UninitializedPropertyAccessException
}
}
fun resetField(target: Any, fieldName: String) {
val field = target.javaClass.getDeclaredField(fieldName)
with (field) {
isAccessible = true
set(target, null)
}
}
fun main() {
MyClass().test()
}
So, setting that field to null (and it's possible only via reflection) makes this filed uninitialized again. And one important thing - treat it as a curiosity, not like thing that should be in your production code.

bind 'lateinit' modifier with condition in Kotlin

In Kotlin, we have lateinit modifier to lazy variable initialization instead of var something: Something? = null.
In my situation, I have a list of the Element, and I want to assign it to the lateinit variable when I having the first object.
So, I tried several methods to achieve this.
First, using 'firstOrNull()' methods
lateinit var applicationHolder: ApplicationHolder
applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
The first solution was failed because applicationHolder doesn't accept the Nullable type of ApplicationHolder. (Type inference failed. Expected type mismatch: inferred type is ApplicationHolder? but ApplicationHolder was expected.)
Although I can use first instead of firstOrNull to achieve this, it's too dangerous because the list can be empty.
Second, using if-condition
val item = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
if (item != null) {
applicationHolder = item
}
The second solution was succeeded to compile and working well.
Third, using backing properties (Actually, this solution don't use lateinit modifier)
val applicationHolder: ApplicationHolder
get() {
return _applicationHolder ?: throw NullPointerException("Not initialized")
}
private var _applicationHolder: ApplicationHolder? = null
_applicationHolder = env.getElementsAnnotatedWith(InjectApplication::class.java)
.map {
ApplicationHolder(it, (it as TypeElement).asClassName(), it.simpleName.toString()).apply {
val component = it.getAnnotation(InjectApplication::class.java).getComponent()
componentClass = component
}
}.firstOrNull()
The third solution was succeeded to compile and working well.
In short, my question is as follows.
Is there a better solution to achieve my goal than these solutions?
If another solution doesn't exist, which is a clean or better solution? I can use the second or third solution but I have no confidence which is clean or better.
Why are you using lateinit over a nullable type here?
This strikes warning bells to me :
it's too dangerous because the list can be empty.
If you try to access a lateinit object without initialising it, your application will crash. Lateinit should be use if it will definitely be initialised.
I would change the code to what you were avoiding : var something: Something? = null
Then use the firstOrNull() method. The kotlin null safety type system will enforce you deal with nulls, leading to safe code!
It is possible to check whether a lateinit has been initialised, by calling this::applicationHolder.isInitialized.  (This was introduced in Kotlin 1.2; info here.)
However, as per #user8159708's answer, it still smells a bit.  Reworking to make the property nullable will make it slightly more awkward to access, but much safer.

Kotlin, set var/val once to make it final, is that possible

In Kotlin, we have val that is final and can't be change. e.g.
val something = "Something"
If a value that is is initialized later, we use lateinit var.
lateinit var something: String
But this is var instead of val. I wanted to set something once (not in constructor), and have it as final. How could I achieve this?
Reading into the conventions of Kotlin, a late-initialized variable which is final is impossible.
Consider its use case:
Normally, properties declared as having a non-null type must be initialized in the constructor. However, fairly often this is not convenient. For example, properties can be initialized through dependency injection, or in the setup method of a unit test. In this case, you cannot supply a non-null initializer in the constructor, but you still want to avoid null checks when referencing the property inside the body of a class.
lateinit var is providing relative sanity when dealing with a variable that may not have yet been initialized, such as the case with injected fields (like Spring and #Autowired). Then, speaking strictly in the context of dependency injection, if you don't have a way to concretely instantiate the variable at compile time, then you cannot leave it as a final field.
From a Java to Kotlin world, having a late initialized variable come in as final would look as paradoxical as this from Spring:
#Autowired
private final Interface something;
What do you think the behavior should be when you attempt to set it again? Do you expect this to be enforced at compile time? Should it cause a crash at runtime or just do nothing?
If you expect it to happen at compile time, I'm pretty sure it's not possible for a compiler to catch something like that.
If you want some other behavior, you can make it a private variable with a public set method that does whatever you want if it's been already set.
Or you could encapsulate it in an instance of a custom class that does whatever behavior you want.
You can use following delegate class:
import kotlin.reflect.KProperty
class WriteOnce<T> {
private var holder = holdValue<T>()
private var value by holder
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
if (!holder.hasValue) {
throw IllegalStateException("Property must be initialized before use")
}
return value
}
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
if (holder.hasValue) {
throw RuntimeException("Write-once property already has a value")
}
this.value = value
}
}
fun <T> holdValue() = ValueHolder<T>()
class ValueHolder<T> {
var value: T? = null
var hasValue: Boolean = false
private set
operator fun setValue(thisRef: Any?, property: KProperty<*>, value: T) {
this.value = value
hasValue = true
}
operator fun getValue(thisRef: Any?, property: KProperty<*>): T {
return this.value!!
}
}
Usage:
var example by WriteOnce<String>()
If you try to write a to the variable a second time it will produce a RuntimeException:
java.lang.RuntimeException: Write-once property already has a value
Not having any value also produces an exception, similar to as if you were using lateinit:
java.lang.IllegalStateException: Property must be initialized before use
Which means this is val and lateinit combined because you can set the value at any time, only once ever.
The downside to this implementation is that this is not checked at compile time, meaning that you will only ever see errors in runtime. If that's acceptable in your use case, it certainly would be a good solution for what you're looking for.
For me this is more of a way to make sure that a variable is only every assigned once by code I control – something I can catch during testing as well as in production as a way to improve security by preventing foreign code from changing a variable.
It is possible you can use You can create a custom delegate for the property that is a combination of the existing notNull delegate and your own idea of set once. Read more about property delegates for information on how to create a custom one that can do whatever you want, including the use case you want here. You would then not use lateinit but instead this delegate.