what's different between the two?
fun main(args: Array<String>) {
var a = printName("Jennie")
var b = printName("Jennie")
println(a == b) // compiler : false
var c = "Robert"
var d = "Robert"
println(c == d) // compiler : true
}
class printName(val name : String)
when I use the class, the result is false even if the String type is the same. but if I don't use class, then what happens is true.
If you want to use class, you must override equals and hashcode. But you can also use data class if you want to compare objects as equals and hashcode is already handled in data class.
In your case, c and d are references to the same String instance. (The compiler sees that the two string literals are the same, and merges them.) But even if they were different String instances, they'd still compare as equal. That's because == calls the equals() method, and String overrides that to return true if the two strings have the same characters.
In your first case, a and b are references to different printName* instances. (printName() is a call to its constructor, so each call returns a new instance.) And your printName class does not override equals(), so it inherits the default implementation from its superclass (Any). And that implementation always returns false for different instances, regardless of whether their contents are the same.
If you want different printName instances to compare as equal if they have the same contents, then you should override its equals() method. You could do that manually, e.g.:
class PrintName(val name: String) {
override fun equals(other: Any?) = other is PrintName
&& name == other.name
}
Or you could make it a data class, which does that automatically. (It also adds toString() and several other useful methods, but has some restrictions around constructors and inheritance.)
Another option might be to share or cache printNames instead of creating a new one each time.
(* By the way, it's conventional to use class names that start with a capital letter, so they stand out.)
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 trying to access the delegate of the property (id) of a class (FooImpl). The problem is, this class implements an interface (Foo), and the property in question overrides a property of this interface. The delegate only exists in the class (not that it could exist in the interface).
The problem is that using the :: operator on a variable of type Foo always returns the property of Foo, not that of the actual instance. The problem in code:
import kotlin.reflect.KProperty
import kotlin.reflect.KProperty0
import kotlin.reflect.jvm.isAccessible
interface Foo {
val id: Int
}
class FooImpl(
id: Int,
) : Foo {
override val id: Int by lazy { id }
}
val <T> KProperty<T>.hasDelegate: Boolean
get() = apply { isAccessible = true }.let { (it as KProperty0<T>).getDelegate() != null }
fun main() {
val foo: Foo = FooImpl(1)
println("foo::id.hasDelegate = ${foo::id.hasDelegate}")
println("(foo as FooImpl)::id.hasDelegate = ${(foo as FooImpl)::id.hasDelegate}")
}
This prints:
foo::id.hasDelegate = false
(foo as FooImpl)::id.hasDelegate = true
But this requires compile-time knowledge of the correct implementation. What I'm looking for is accessing the correct propert without having to specify FooImpl there.
The information is present at runtime because the least (!) intrusive workaround I have found so far is adding fun idProp(): KProperty0<*> to Foo and override fun idProp() = ::id to FooImpl and accessing the property using that.
Is there any better way than that?
I came up with this, but I don't know if there's a better way. The problem to work around is that getDelegate() has to return an actual instance of the delegate, so you need an instance of the class to be able to retrieve a delegate instance. It would really be nice if there was a hasDelegate property built in. Your version of hasDelegate will crash from the cast on unbound KProperty1's, which is all we have to work with when the specific class is unknown.
So to retrieve the delegate instance, we need to do search the class instance's member properties by name, which gives us a KProperty with covariant class type of the super-class type. Since it's covariant, we can call a consuming function like getDelegate() without casting to the invariant type. I think this logically should be safe, since we are passing an instance that we know has the matching type for the ::class that we retrieved the property with.
#Suppress("UNCHECKED_CAST")
fun <T: Any> KProperty1<T, *>.isDelegated(instance: T): Boolean =
(instance::class.memberProperties.first { it.name == name } as KProperty1<T, *>).run {
isAccessible = true
getDelegate(instance) != null
}
fun main() {
val foo: Foo = Foo2()
println("foo::id.hasDelegate = ${Foo::id.isDelegated(foo)}")
}
The problem here is that the owner of the property is resolved on compile time, not on runtime. When you do foo::id then foo (so FooImpl) become its bound receiver, but owner is still resolved to Foo. To fix this we wound need to "cast" property to another owner. Unfortunately, I didn't find a straightforward way to do this.
One solution I found is to use foo::class instead of foo::id as it resolves KClass on runtime, not on compile time. Then I came up with almost exactly the same code as #Tenfour04.
But if you don't mind using Kotlin internals that are public and not protected with any annotation, you can use much cleaner solution:
val KProperty0<*>.hasDelegate: Boolean
get() = apply { isAccessible = true }.getDelegate() != null
fun KProperty0<*>.castToRuntimeType(): KProperty0<*> {
require(this is PropertyReference0)
return PropertyReference0Impl(boundReceiver, boundReceiver::class.java, name, signature, 0)
}
fun main() {
val foo: Foo = FooImpl(1)
println(foo::id.castToRuntimeType().hasDelegate) // true
}
We basically create a new instance of KProperty, copying all its data, but changing the owner to the same type as its bound receiver. As a result, we "cast" it to the runtime type. This is much simpler and it is also cleaner because we separated property casting and checking for a delegate.
Unfortunately, I think Kotlin reflection API is still missing a lot of features. There should be hasDelegate() function, so we don't have to provide receivers, which is not really needed to check if property is delegated. It should be possible to cast KProperty to another type. It should be possible to create bound properties with some API call. But first of all, it should be possible to do something like: Foo::id(foo), so create KProperty of the runtime type of foo. And so on.
Lets imagine we have sealed class with data classes and objects inside:
sealed class CarEvent {
data class FilledFuel(val fuelAmount: Float) : CarEvent()
data class ChangedPart(val part: CarPart) : CarEvent()
object StartedEngine : CarEvent()
}
Then we have when statement reducing events:
when(event) {
is CarEvent.FilledFuel -> { do something }
is CarEvent.ChangedPart -> { do something }
CarEvent.StartedEngine -> { do something }
}
The questing is: what is the most true approach for StartedEngine object:
compare it using is operator, or without is operator (using default == inside when statement).
Is there any difference between these two?
Is there any difference between these two?
Yes, is checks if something is an instance of a specific type, where as == will check if one object is the same as another
As an example:
val foo = 5
val result = foo is Int
This will always be true, because foo is a type of integer.
but if you consider
val foo = 5
val result = foo == 7
This will return false, correctly, because these two values aren't the same thing.
In your case, I don't think it would matter, but is would probably make more sense
When has a syntatic sugar of evaluating what's inside parentheses versus each case
When you put nothing, it checks for equality and in other cases it checks what you put there
In case of objects, kotlin creates a class for them and creates a singleton INSTANCE and if you try to look at it from a Java point of view, when you put is StartedEngine it's like checking event instanceof StartedEngine and when put StratedEngine it's like event.equals(StartedEngine.INSTANCE)
so one of them check for type while the other checks for equality
On the other hand, object are strictly singletons which you cannot inherit, or override anything from them so it doesn't matter if you check for equality or is unless you've override equals in that object.
So they're not different in usage, nor in action. They are just different approaches.
sealed class A{
abstract val name:String
object AAA : A(){
override val name get()= "AA"
override fun equals(o: Any?) : Boolean {
println("AAA equality call")
return super.equals(o)
}
}
object BBB : A() {
override val name get()="BB"
}
}
fun main() {
val o : A = A.AAA
when(o){
is A.AAA -> println("o is AAA")
}
when(o){
A.AAA -> println("o==AAA")
}
}
But notice that if the override fun equals in AAA returned false, o==AAA wouldn't get printed also note that in second when, equals gets called and it prints AAA equality call
Output
o is AAA
AAA equality call
o==AAA
Here an equals overloading
class MyClass {
...
val string: String = ...
override operator fun equals(other: Any?): Boolean {
if (other != null) else { return false }
if (other is MyClass && string == other.string) { return true }
if (other is String && string == other) { return true }
return false
}
...
}
The idea is to be able to compare:
myClass1 = MyClass("ABCDEF")
myClass2 = MyClass("ABC123")
myClass1 == fsPath2 >> false
or
myClass1 == "ABC123" >> false
But the precompiled says: Operator '==' cannot be applied to 'MyClass' and 'String'
Any idea?
I'm afraid this can't work the way you want.
In order for equality to behave the way everyone expects, it has a very specific contract. (The docs for the Kotlin Any.equals() method spell out all the necessary conditions, and the docs for the Java Object.equals() method have a bit more info.)
One of the conditions is that the equality relation must be reversible: a == b if and only if b == a. (In technical terms, the relation must be symmetric.)
But that's not true of your implementation:
myClass1.equals("ABCDEF") returns true (from MyClass's implementation of equals()), but
"ABCDEF".equals(myClass1) returns false (from calling String's implementation)
A system class like String doesn't know about your class, and there's no way to change its equals() implementation so it does. So unfortunately there's no way to treat it as equal, without breaking the contract.
(You can probably imagine some of the subtle bugs that could cause: for example, a Set could hold both of those objects, or just one, depending on the order they happened to be added in…)
The compiler error you're getting is an indirect result of this: assuming the equals() contract holds, unrelated classes are never going to be treated as equal, so the compiler won't even let you try to compare them that way.
Because of the strict contract, you need to take great care when implementing equals(); as well symmetry, it's easy to break transitivity and/or consistency, and you need to override hashCode() to match. See for example these articles. (And even if you control both classes, it's still surprisingly tricky to get equality working between them; this article explains the issues rather well.)
java.lang.StackOverflowError
at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:164)
at plugin.interaction.inter.teleports.Category.equals(Category.kt)
at kotlin.jvm.internal.Intrinsics.areEqual(Intrinsics.java:164)
at plugin.interaction.inter.teleports.Destination.equals(Destination.kt)
Happens from a .equals comparison between two non-relationship data classes.
Major bug.
data class Category(val name: String, val destinations: MutableList<Destination>)
data class Destination(val category: Category, val name: String)
Data classes in Kotlin are just syntactic sugar for Java POJOs.
The main culprit in your example is this cycle:
val destinations: MutableList<Destination> in Category &
val category: Category in Destination
You must remove this cycle by moving either of the two variables out of the primary data class constructor.
However, there is also a much bigger sideeffect: data class Category(..) is mutable, which will cause for it (and any other data class using categories in it's primary constructor!) to be unsafe to use as keys in any hash-based collection. For more information, see: Are mutable hashmap keys a dangerous practice?
Given that data classes are meant for pure data, I recommend removing val category: Category in data class Destination(..), and change type of val destinations: MutableList<Destination> in data class Category(..) to read-only List<Destination>. In order to break immutable state after said changes, you will have to either perform unsafe casts from Kotlin or create an instance of the class from Java.
If you however absolutely require a backreference to categories in destinations (and aren't using your classes in hashmaps/-sets/etc.), you could either make Destination a regular class and implement equals/hashCode yourself, or move the category out of the primary constructor. This is a bit tricky, but can be done with a secondary constructor:
data class Destination private constructor(val name: String) {
private lateinit var _category: Category
val category get() = _category
constructor(category: Category, name: String) : this(name) {
_category = category
}
}
Well in my case I was overriding equals method like:
override fun equals(other: Any?): Boolean {
// some code here
if (other==this)
return true
// some code here
}
equals and == in java
In java when we use equals(for ex: str1.equals(str2)) it checks the content of two object(for custom objects you must have to override equals and check all the values of objects otherwise Object class's equals method just compare reference, which is same as ==), but if we use ==(for ex: str1==str2) operator, it checks the reference of both objects.
== in kotlin
But in case of kotlin when we use == operator, it checks the content(data or variable) of objects only if they are object of data class. And == operator checks reference for normal class.
when we use == it will call the equals method.
So in my overridden equals method when other==this will execute it will call eaquals method again, and that will call eaquals method again and make an infinite loop.
So to make it work we need to change == to ===(this will check the reference of both operator), like:
if (other===this)
return true
Note: .equals and == are same until we use them with Float or
Double. .equals disagrees with the IEEE 754 Standard for
Floating-Point Arithmetic, it returns a false when -0.0 was compared
with 0.0 whereas == and === returns true
You can check reference here