Are these equivalent?
val foo = someFooReturningFunction()
val foo get() = someFooReturningFunction()
The way I understood the documentation they were, but in my own testing they are not.
With the get() someFooReturningFunction() is evaluated each time the property is accessed, without it is only evaluated once.
They are not equivalent. The custom getter is indeed evaluated on each property access, similarly to a normal function, while a val property with no custom accessors is only evaluated once on initialization (and is actually stored in a final field on JVM platform).
Here are at least a few more differences:
The control flow analysis and nullability inference takes it into account if a property has a custom getter (or is open and thus might be overridden with a custom getter), because there's no guarantee that the property returns the same value on successive calls:
if (someObject.defaultGetterProperty != null) {
someObject.defaultGetterProperty.let { println(it) } // OK
}
if (someObject.propertyWithCustomGetter != null) {
someObject.propertyWithCustomGetter { println(it) } // Error: cannot smart-cast
}
When a property is private, if it has no custom getter then the getter is not generated at all and the backing field is accessed directly. This, however, is an implementation detail and not something to rely on.
No. In addition to #hotkey's reasons, here's a simple demonstration using mutable properties showing when they're definitely not equivalent. TLDR: if your property is calculated using a mutable property, always use a custom getter over an initializer.
data class Calculation(val value1: Int, var value2: Int) {
val sum: Int = value1 + value2
val sumWithGetter: Int
get() = value1 + value2
}
val calculation = Calculation(1, 2)
println(calculation.sumWithGetter) // prints 3
println(calculation.sum) // prints 3
calculation.value2 = 0
println(calculation.sumWithGetter) // prints 1 (correct)
println(calculation.sum) // prints 3!
Related
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!
I'm new to Kotlin and I'm trying to understand it, I've just written a simple example that shows how using data classes with maps is a bit tricky, because it seems to me that data classes have a strange behaviour. By default, they define hashCode() based on every property of the class. But they don't define a default equals() method.
This caused to me a lot of confusion because I created a HashMap with a Data Class as a key, but I didn't override hashCode() and equals(). My data class has a MutableList member. When I put an element in the map, I retrieved it using map.get(dataObject) as long as I didn't add an element to the MutableList. After that, even if the data object was still the same, and I found it using map.keys (map.keys.indexOf(dataObject) works), map.get(dataObject) failed, due to the hashCode().
I can fix it using a normal class or adding hashCode() and equals(), removing the MutableList from hashCode(), but I'm wondering if, due to the default behaviour, overriding hashCode() and equals() should be "mandatory" with data classes because otherwise using them with Maps can lead to errors.
Is there something else I can do to avoid this problem?
package cards
data class Player(val name: String, var cards: MutableList<Card>) {
constructor(name: String): this(name, mutableListOf())
//I don't need to define equals, so pointers are checked. But if I don't override hashCode, as it's based
//on every property, the hashCode is calculated considering the content of the MutableList!
// override fun hashCode(): Int {
// return name.hashCode()
// }
}
data class Card(val name: String, val suite: String)
class Game(val players: List<Player>) {
val cardMap: MutableMap<Player, MutableList<Card>> = mutableMapOf()
fun putIntoMapAndGiveCards() {
val newCards = cardMap.getOrDefault(players[0], mutableListOf())
newCards.add(Card(name = "Four", suite = "Clubs"))
cardMap[players[0]] = newCards
//This changes the default hashCode - I can use data classes in a list, but not in a map, because maps are
//based on it.
players[0].cards.add(Card(name = "Five", suite = "Clubs"))
}
fun getFromMap(): MutableList<Card>? {
val player = players[0]
assert(player != null, { "Player from list failure" })
val indexOfPlayer = cardMap.keys.indexOf(player)
assert(indexOfPlayer == 0, { "Player is in the map" })
//Without overriding hashCode, cards is null!
val cards = cardMap.get(players[0])
assert(cards != null, { "Cards from map failure" })
return cards
}
}
fun main() {
val player1 = Player(name = "John")
val game = Game(mutableListOf(player1))
game.putIntoMapAndGiveCards()
game.getFromMap()
?: throw Exception( """Map.get() failure because Player is a data class.
| A data class by default builds its hashCode with every property. As it contains a MutableList,
| the hashCode changes when I add elements to the list. This means that I can't find the element using get()
""".trimMargin())
println("Test finished!")
}
By default, they define hashCode() based on every property of the class. But they don't define a default equals() method
This is not correct. Data classes generate both equals() and hashCode() consistently based on the properties declared in the data class's primary constructor (same goes for toString() btw).
Here is the decompiled code for equals and hashCode of your Player class:
public int hashCode() {
String var10000 = this.name;
int var1 = (var10000 != null ? var10000.hashCode() : 0) * 31;
List var10001 = this.cards;
return var1 + (var10001 != null ? var10001.hashCode() : 0);
}
public boolean equals(#Nullable Object var1) {
if (this != var1) {
if (var1 instanceof Player) {
Player var2 = (Player)var1;
if (Intrinsics.areEqual(this.name, var2.name) && Intrinsics.areEqual(this.cards, var2.cards)) {
return true;
}
}
return false;
} else {
return true;
}
}
Your problem is that you declare your cards mutable list in the primary constructor so it's part of the generated equals and hashCode.
The solution is to move this cards property to the body of your class instead (since it's not part of the player's "core data", but rather part of the state):
data class Player(val name: String) {
val cards: MutableList<Card> = mutableListOf()
}
This way, the generated equals/hashCode pair will only be based on the name property.
Another option obviously is to override both equals and hashCode manually to take only the name into account, but that's tedious and not very idiomatic.
I'm wondering if, due to the default behaviour, overriding hashCode() and equals() should be "mandatory" with data classes because otherwise using them with Maps can lead to errors.
I think you have misdiagnosed the default behaviour. So I'd say on the contrary overriding equals/hashCode is actually not very idiomatic for data classes, and should in general be avoided.
Using data classes is usually safe in maps, as long as the data in the primary constructor is not mutable.
Side notes
you really should not mix var with mutable collections. It creates 2 ways of changing the collection, which is pretty unexpected and error-prone. You should instead either use a val MutableList or a var List, so you can only change the list via mutation, or only change it via assignment, but not both.
if you want to insert the new value into the map, you shouldn't use getOrDefault + assign the value to the key. Instead, use getOrPut directly, so the default value will be inserted without extra work.
why are you both using a cards property on the Player and a Map<Player, List<Card>>? Looks like you have 2 states that can change independently now because those card lists are independent.
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!
I started playing arround with Kotlin and read something about mutable val with custom getter. As refered in e.g here or in the Kotlin Coding Convention one should not override the getter if the result can change.
class SampleArray(val size: Int) {
val isEmpty get() = size == 0 // size is set at the beginning and does not change so this is ok
}
class SampleArray(var size: Int) {
fun isEmpty() { return size == 0 } // size is set at the beginning but can also change over time so function is prefered
}
But just from the perspective of usage as in the guidelines where is the difference between the following two
class SampleArray(val size: Int) {
val isEmpty get() = size == 0 // size can not change so this can be used instad of function
val isEmpty = size == 0 // isEmpty is assigned at the beginning ad will keep this value also if size could change
}
From this answer I could see that for getter override the value is not stored. Is there something else where the getter override is different form the assignment? Maybe with delegates or latinit?
In your second example size is immutable value and therefore both ways are valid.
However variant with overridden getter get() = size == 0 has no backing field and therefore size == 0 is evaluated every time you access isEmpty variable.
On the other hand, when using initializer = size == 0 the expression size == 0 is evaluated during construction (check exactly when and how here - An in-depth look at Kotlin’s initializers) and stored to the backing field, of which value is then returned when you access the variable.
The key difference here is that in val isEmpty get() = ... the body is evaluated each time the property is accessed, and in val isEmpty = ... the expression on the right hand side gets evaluated during the object construction, the result is stored in the backing field and this exact result is returned each time the property is used.
So, the first approach is suitable when you want the result to be calculated each time, while the second approach is good when you want the result to be calculated only once and stored.
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