equal() function in Kotlin - kotlin

I need if two objects are equal() need to print("Equal") if objects are not equal -> "Not equal".I can not find mistake of this codeThis is my code in IntelliJ IDEA
As a side note, when we override equals(), it is recommended to also override the hashCode() method. If we don’t do so, equal objects may get different hash-values; and hash based collections, including HashMap, HashSet, and Hashtable do not work properly (see this for more details). We will be covering more about hashCode() in a separate post.
References:
internal class Complex(private val re: Double, private val im: Double) {
// Overriding equals() to compare two Complex objects
fun equals(o: Object): Boolean {
// If the object is compared with itself then return true
if (o === this) {
return true
}
/* Check if o is an instance of Complex or not
"null instanceof [type]" also returns false */if (o !is Complex) {
return false
}
// typecast o to Complex so that we can compare data members
val c = o as Complex
// Compare the data members and return accordingly
return (java.lang.Double.compare(re, c.re) == 0
&& java.lang.Double.compare(im, c.im) == 0)
}
} // Driver class to test the Complex class
fun main(args: Array<String>) {
val c1 = Complex(12.0, 15.0)
val c2 = Complex(10.0, 15.0)
if (c1 == c2) {
println("Equal ")
} else {
println("Not Equal ")
}
}

In Kotlin, you use Any instead of Object. It will not allow you to test if your class instance is an Object, only Any.
Also, you are failing to override equals since you didn't use the override keyword. The argument needs to be Any?, not Object.
Change
fun equals(o: Object): Boolean {
to
override fun equals(o: Any?): Boolean {
Also, in this case, you should use a data class so you won't have to write your own equals() implementation in the first place.
And in the future, when you aren't using a data class, you can use the IDE option to generate equals and hashcode for you automatically.

A data class would make more sense:
data class Complex(
private val re: Double,
private val im: Double
)
val c1 = Complex(12.0, 15.0)
val c2 = Complex(10.0, 15.0)
if (c1 == c2) {
println("Equal")
} else {
println("Not Equal")
}
Output: Not Equal

Related

What is the type of a Kotlin 'data class'?

I have a situation where I need to create a copy of data class object. I don't know in advance which of the many data classes I have will come in into the function. I do know, however, that only data classes will be used as input to this function.
This is what didn't work:
fun doSomething(obj: Any): Any {
obj.copy(...) // <- there's no 'copy' on Any
...
}
This is what I really like to do:
fun doSomething(obj: KAnyDataClass): KAnyDataClass {
obj.copy(...) // <- works, data classes have a 'copy' method
...
}
I'm not a Kotlin developer, but it looks like the language does not support dynamic dispatch or traits. You might find success with the dynamic type, which just turns off the type-checker so it won't yell at you for using a method that it doesn't know about. However this opens up the possibility of a runtime error if you pass an argument that actually doesn't have that method.
There is no class or interface for data classes, but we know from the documentation of data classes that there are derived functions componentN and copy in each data class.
We can use that knowledge to write an abstract copy method that calls the copy method of a given arbitrary data class using reflection:
fun <T : Any> copy(data: T, vararg override: Pair<Int, Any?>): T {
val kClass = data::class
if (!kClass.isData) error("expected a data class")
val copyFun = kClass.functions.first { it.name == "copy" }
checkParameters(override, kClass)
val vals = determineComponentValues(copyFun, kClass, override, data)
#Suppress("UNCHECKED_CAST")
return copyFun.call(data, *vals) as T
}
/** check if override of parameter has the right type and nullability */
private fun <T : Any> checkParameters(
override: Array<out Pair<Int, Any?>>,
kClass: KClass<out T>
) {
override.forEach { (index, value) ->
val expectedType = kClass.functions.first { it.name == "component${index + 1}" }.returnType
if (value == null) {
if (!kClass.functions.first { it.name == "component${index + 1}" }.returnType.isMarkedNullable) {
error("value for parameter $index is null but parameter is not nullable")
}
} else {
if (!expectedType.jvmErasure.isSuperclassOf(value::class))
error("wrong type for parameter $index: expected $expectedType but was ${value::class}")
}
}
}
/** determine for each componentN the value from override or data element */
private fun <T : Any> determineComponentValues(
copyFun: KFunction<*>,
kClass: KClass<out T>,
override: Array<out Pair<Int, Any?>>,
data: T
): Array<Any?> {
val vals = (1 until copyFun.parameters.size)
.map { "component$it" }
.map { name -> kClass.functions.first { it.name == name } }
.mapIndexed { index, component ->
override.find { it.first == index }.let { if (it !== null) it.second else component.call(data) }
}
.toTypedArray()
return vals
}
Since this copy function is generic and not for a specific data class, it is not possible to specify overloads in the usual way, but I tried to support it in another way.
Let's say we have a data class and element
data class Example(
val a: Int,
val b: String,
)
val example: Any = Example(1, "x")
We can create a copy of example with copy(example) that has the same elements as the original.
If we want to override the first element, we cannot write copy(example, a = 2), but we can write copy(example, 0 to 2), saying that we want to override the first component with value 2.
Analogously we can write copy(example, 0 to 3, 1 to "y") to specify that we want to change the first and the second component.
I am not sure if this works for all cases since I just wrote it, but it should be a good start to work with.

What is the difference between Comparable and operator compareTo?

Lets say I have class A(val foo: Double).
I want to be be able to compare it to other A, Double, and Int.
If I implement Comparable, I can only compare it against one other object type.
override fun compareTo(other: A): Int {
return when {
this.foo == other.foo -> 0
this.foo > other.foo -> 1
else -> -1
}
}
But I've also seen extension functions overriding the compareTo operator.
operator fun A.compareTo(d: Double): Int {
return when {
this.foo == d -> 0
this.foo > d -> 1
else -> -1
}
}
What is the difference between these and what should I be using? I'm guessing if I want to compare it to multiple types then I have to use extension functions?
The Comparable interface comes from Java, and, as you have seen, is defined with only a compareTo( other) method, which only provides for comparing an object to another object of the same type.
As you have also noticed, the Kotlin extension functions are additional functions allowing you to compare an object to whatever you want, as long as you define the compareTo method to take an argument of the type to which you want to compare.
So, yes, if you want to compare an object to an object of a different type, you will need to write an appropriate extension function.
Of course, in Java, if you have control of the source code of the class, you can always add a custom compareTo method.
Comparable is a standard interface, it's the way you define a class as having some ordering, and every library that deals with ordering works with Comparable types. Basically, if you want to be able to order and compare your things using all the standard functions and anything anyone else might write, you need to implement the Comparable interface.
This works:
data class SportsTeam(val name: String) : Comparable<SportsTeam> {
override fun compareTo(other: SportsTeam): Int = when {
name == "best team" -> 1
other.name == "best team" -> -1
else -> 0
}
}
fun main(args: Array<String>) {
val best = SportsTeam("best team")
val worst = SportsTeam("worst team")
print("The winner is: ${maxOf(best, worst).name}")
}
but because maxOf takes a Comparable type, this won't work:
data class SportsTeam(val name: String)
fun SportsTeam.compareTo(other: SportsTeam): Int = when {
name == "best team" -> 1
other.name == "best team" -> -1
else -> 0
}
fun main(args: Array<String>) {
val best = SportsTeam("best team")
val worst = SportsTeam("worst team")
print("The winner is: ${maxOf(best, worst).name}")
}
Wenn you make your own objects you must implement Comparable interface and then override compareTo function
class MyClass : Comparable<MyClass> {
override fun compareTo(other: MyClass): Int {
// TODO Returns zero if this object is equal to the specified other object
}
}
You can also override an operator function, for example from Int class in kotlin
fun main(args: Array<String>) {
val a = 1
val b = "2"
println(a.compareTo(b))
}
operator fun Int.compareTo(i: String) : Int {
return if (this.toString() == i) {
0
} else {
1
}
}
I hope that's helpfull from you

How to deal with nullable values in Iterator implementation in kotlin?

So I was following the Algorithms book by Sedgewick and trying to translate the implementations from Java to Kotlin and when I tried to implement one Iterator for the Bag data structure (that's essentially a one-way linked list), I got stuck with nullability issues and thread safety in Kotlin.
The implementation in java from the book is done this way:
public class Bag<Item> {
private Node first;
private class Node {
Item item;
Node next;
}
/* some methods */
private class Iterator<Item> {
private Node current = first;
public boolean hasNext() { current != null; }
public Item next() {
if (!hasNext()) throw new NoSuchElementException();
Item item = current.item;
current = current.next;
return item;
}
}
}
which I tried to implement in Kotlin like this:
class Bag<Item> : Iterable<Item> {
private inner class Node(val item: Item, val next: Node?)
private var first : Node? = null
/* Some methods */
override fun iterator() = object : Iterator<Item> {
private var current : Bag<Item>.Node? = first
override fun hasNext() : Boolean = current != null
override fun next() : Item {
if (current == null) throw NoSuchElementException()
val item = current.item
current = current.next
return item
}
}
}
But I got the following error:
Smart cast to 'Bag.Node' is impossible, because 'current' is a mutable property that could have been changed by this time
I understand this is due to race condition between checking if the variable is null and actually accessing the variable attributes, since the variable could be set to null by other threads. After some time I arrived into the following implementation:
override fun iterator() = object : Iterator<Item> {
private var current : Bag<Item>.Node? = first
override fun hasNext() : Boolean = current != null
override fun next() : Item {
current?.let {
val item = it.item
current = it.next
return item
} ?: throw NoSuchElementException()
}
}
And the compiler thought this was fine. But I still have some doubts. Which leads to my questions:
1) Is the assignment current = it.next thread safe or should I assign to the implicit it instead?
2) Is there a idiomatic Kotlin way of implementing an iterator of non-nullable type that ends with a null value? (meaning that all values in it are non-null except for the ending condition)
Is the assignment current = it.next thread safe
It is not thread safe.
Imagine a list of integers and two threads A and B who want to use iterator instance I.
1 -> 2 -> 3 -> 4 -> 5 A: item=1, next=(2)
^ A: item=1, next=(2)
I
Both threads begin to iterate. Both path inside current?.let. Both read current item (val item = it.item) and got item=1, next=(2). Then, first thread A is frozen and second thread B advances the iterator, let's say, by three items forward:
1 -> 2 -> 3 -> 4 -> 5 A: item=1, next=(2)
^ B: item=4, next=(5)
I
Now B enters let and reads next item: item=4, next=(5). Remember that A is still in his loop and it's item is item=1, next=(2). If B is now frozen and A advances one line of code (current = it.next) then things are broken: current is a shared state (as it is stored in the iterator) and, thus, B will see the change as well. On the next iteration in B it will be "thrown back" to the item #2. Nothing bad will happen and the program will not fail, but most probably that is not the behavior you need.
Even more: for the described reasons iterators are not meant to be thread-safe and every thread should have it's own, independent one. Things become more interesting with iterators that change a collection (insertions / deletions), but it's another story as it is about the collection, not about the iterator.
Should I assign to the implicit it instead?
You cannot assign to it, as it is a function parameter and it is passed by value, and, thus, cannot be changed. The compiler will ban the assignment with a message like "Val cannot be reassigned"
Is there a idiomatic Kotlin way of implementing an iterator of non-nullable type that ends with a null value?
I'd say: yes. You could potentially use sealed classes to designate different types of nodes like:
sealed class Node<out T>;
object Empty : Node<Nothing>();
data class Full<T>(val item: T, val next: Node<T>) : Node<T>();
class Bag<T>(private val first: Node<T>) : Iterable<T> {
override fun iterator(): Iterator<T> = object : Iterator<T> {
private var current = first
override fun hasNext() = current !is Empty
override fun next() = when (val c = current) {
Empty -> throw IllegalStateException()
is Full -> {
current = c.next
c.item
}
}
}
}
fun main() {
val bag = Bag(Full(1, Full(2, Full(3, Empty))))
bag.forEach(::println)
}
I was surprised to not see this method listed, which has been available since Kotlin 1.3. You can use the iterator {} helper in conjunction with yield() to easily build an iterator that handles null effectively.
For example, in a LinkedList:
class NamedLinkedListNode(
val name: String,
val next: NamedLinkedListNode?
) : Iterable<String> {
override fun iterator() = iterator {
var node: NamedLinkedListNode? = this#NamedLinkedListNode
while (node != null) {
yield(node.name)
node = node.next
}
}
}

How do I create an enum from an Int in Kotlin?

I have this enum:
enum class Types(val value: Int) {
FOO(1)
BAR(2)
FOO_BAR(3)
}
How do I create an instance of that enum using an Int?
I tried doing something like this:
val type = Types.valueOf(1)
And I get the error:
Integer literal does not conform to the expected type String
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun fromInt(value: Int) = Types.values().first { it.value == value }
}
}
You may want to add a safety check for the range and return null.
Enum#valueOf is based on name. Which means in order to use that, you'd need to use valueof("FOO"). The valueof method consequently takes a String, which explains the error. A String isn't an Int, and types matter. The reason I mentioned what it does too, is so you know this isn't the method you're looking for.
If you want to grab one based on an int value, you need to define your own function to do so. You can get the values in an enum using values(), which returns an Array<Types> in this case. You can use firstOrNull as a safe approach, or first if you prefer an exception over null.
So add a companion object (which are static relative to the enum, so you can call Types.getByValue(1234) (Types.COMPANION.getByValue(1234) from Java) over Types.FOO.getByValue(1234).
companion object {
private val VALUES = values()
fun getByValue(value: Int) = VALUES.firstOrNull { it.value == value }
}
values() returns a new Array every time it's called, which means you should cache it locally to avoid re-creating one every single time you call getByValue. If you call values() when the method is called, you risk re-creating it repeatedly (depending on how many times you actually call it though), which is a waste of memory.
Admittedly, and as discussed in the comments, this may be an insignificant optimization, depending on your use. This means you can also do:
companion object {
fun getByValue(value: Int) = values().firstOrNull { it.value == value }
}
if that's something you'd prefer for readability or some other reason.
The function could also be expanded and check based on multiple parameters, if that's something you want to do. These types of functions aren't limited to one argument.
If you are using integer value only to maintain order, which you need to access correct value, then you don't need any extra code. You can use build in value ordinal. Ordinal represents position of value in enum declaration.
Here is an example:
enum class Types {
FOO, //Types.FOO.ordinal == 0 also position == 0
BAR, //Types.BAR.ordinal == 1 also position == 1
FOO_BAR //Types.FOO_BAR.ordinal == 2 also position == 2
}
You can access ordinal value simply calling:
Types.FOO.ordinal
To get correct value of enum you can simply call:
Types.values()[0] //Returns FOO
Types.values()[1] //Returns BAR
Types.values()[2] //Returns FOO_BAR
Types.values() returns enum values in order accordingly to declaration.
Summary:
Types.values(Types.FOO.ordinal) == Types.FOO //This is true
If integer values don't match order (int_value != enum.ordinal) or you are using different type (string, float...), than you need to iterate and compare your custom values as it was already mentioned in this thread.
It really depends on what you actually want to do.
If you need a specific hardcoded enum value, then you can directly use Types.FOO
If you are receiving the value dynamically from somewhere else in your code, you should try to use the enum type directly in order not to have to perform this kind of conversions
If you are receiving the value from a webservice, there should be something in your deserialization tool to allow this kind of conversion (like Jackson's #JsonValue)
If you want to get the enum value based on one of its properties (like the value property here), then I'm afraid you'll have to implement your own conversion method, as #Zoe pointed out.
One way to implement this custom conversion is by adding a companion object with the conversion method:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
private val types = values().associate { it.value to it }
fun findByValue(value: Int): Types? = types[value]
}
}
Companion objects in Kotlin are meant to contain members that belong to the class but that are not tied to any instance (like Java's static members).
Implementing the method there allows you to access your value by calling:
var bar = Types.findByValue(2) ?: error("No Types enum value found for 2")
Note that the returned value is nullable, to account for the possibility that no enum value corresponds to the parameter that was passed in. You can use the elvis operator ?: to handle that case with an error or a default value.
If you hate declaring for each enum type a companion object{ ... } to achieve EMotorcycleType.fromInt(...). Here's a solution for you.
EnumCaster object:
object EnumCaster {
inline fun <reified E : Enum<E>> fromInt(value: Int): E {
return enumValues<E>().first { it.toString().toInt() == value }
}
}
Enum example:
enum class EMotorcycleType(val value: Int){
Unknown(0),
Sport(1),
SportTouring(2),
Touring(3),
Naked(4),
Enduro(5),
SuperMoto(6),
Chopper(7),
CafeRacer(8),
.....
Count(9999);
override fun toString(): String = value.toString()
}
Usage example 1: Kotlin enum to jni and back
fun getType(): EMotorcycleType = EnumCaster.fromInt(nGetType())
private external fun nGetType(): Int
fun setType(type: EMotorcycleType) = nSetType(type.value)
private external fun nSetType(value: Int)
---- or ----
var type : EMotorcycleType
get() = EnumCaster.fromInt(nGetType())
set(value) = nSetType(value.value)
private external fun nGetType(): Int
private external fun nSetType(value: Int)
Usage example 2: Assign to val
val type = EnumCaster.fromInt<EMotorcycleType>(aValidTypeIntValue)
val typeTwo : EMotorcycleType = EnumCaster.fromInt(anotherValidTypeIntValue)
A naive way can be:
enum class Types(val value: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
fun valueOf(value: Int) = Types.values().find { it.value == value }
}
}
Then you can use
var bar = Types.valueOf(2)
Protocol orientated way with type-safety
interface RawRepresentable<T> {
val rawValue: T
}
inline fun <reified E, T> valueOf(value: T): E? where E : Enum<E>, E: RawRepresentable<T> {
return enumValues<E>().firstOrNull { it.rawValue == value }
}
enum class Types(override val rawValue: Int): RawRepresentable<Int> {
FOO(1),
BAR(2),
FOO_BAR(3);
}
Usage
val type = valueOf<Type>(2) // BAR(2)
You can use it on non-integer type, too.
I would build the 'reverse' map ahead of time. Probably not a big improvement, but also not much code.
enum class Test(val value: Int) {
A(1),
B(2);
companion object {
val reverseValues: Map<Int, Test> = values().associate { it.value to it }
fun valueFrom(i: Int): Test = reverseValues[i]!!
}
}
Edit: map...toMap() changed to associate per #hotkey's suggestion.
try this...
companion object{
fun FromInt(v:Int):Type{
return Type::class.java.constructors[0].newInstance(v) as Type
}
}
This is for anyone looking for getting the enum from its ordinal or index integer.
enum class MyEnum { RED, GREEN, BLUE }
MyEnum.values()[1] // GREEN
Another solution and its variations:
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>()[i]
enumFromIndex<MyEnum>(1) // GREEN
inline fun <reified T : Enum<T>> enumFromIndex(i: Int) = enumValues<T>().getOrNull(i)
enumFromIndex<MyEnum>(3) ?: MyEnum.RED // RED
inline fun <reified T : Enum<T>> enumFromIndex(i: Int, default: T) =
enumValues<T>().getOrElse(i) { default }
enumFromIndex(2, MyEnum.RED) // BLUE
It is an adapted version of another answer. Also, thanks to Miha_x64 for this answer.
Another option...
enum class Types(val code: Int) {
FOO(1),
BAR(2),
FOO_BAR(3);
companion object {
val map = values().associate { it.code to it }
// Get Type by code with check existing codes and default
fun getByCode(code: Int, typeDefault_param: Types = FOO): Types {
return map[code] ?: typeDefault_param
}
}
}
fun main() {
println("get 3: ${Types.getByCode(3)}")
println("get 10: ${Types.getByCode(10)}")
}
get 3: FOO_BAR
get 10: FOO

Override getter for Kotlin data class

Given the following Kotlin class:
data class Test(val value: Int)
How would I override the Int getter so that it returns 0 if the value negative?
If this isn't possible, what are some techniques to achieve a suitable result?
After spending almost a full year of writing Kotlin daily I've found that attempting to override data classes like this is a bad practice. There are 3 valid approaches to this, and after I present them, I'll explain why the approach other answers have suggested is bad.
Have your business logic that creates the data class alter the value to be 0 or greater before calling the constructor with the bad value. This is probably the best approach for most cases.
Don't use a data class. Use a regular class and have your IDE generate the equals and hashCode methods for you (or don't, if you don't need them). Yes, you'll have to re-generate it if any of the properties are changed on the object, but you are left with total control of the object.
class Test(value: Int) {
val value: Int = value
get() = if (field < 0) 0 else field
override fun equals(other: Any?): Boolean {
if (this === other) return true
if (other !is Test) return false
return true
}
override fun hashCode(): Int {
return javaClass.hashCode()
}
}
Create an additional safe property on the object that does what you want instead of having a private value that's effectively overriden.
data class Test(val value: Int) {
val safeValue: Int
get() = if (value < 0) 0 else value
}
A bad approach that other answers are suggesting:
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
The problem with this approach is that data classes aren't really meant for altering data like this. They are really just for holding data. Overriding the getter for a data class like this would mean that Test(0) and Test(-1) wouldn't equal one another and would have different hashCodes, but when you called .value, they would have the same result. This is inconsistent, and while it may work for you, other people on your team who see this is a data class, may accidentally misuse it without realizing how you've altered it / made it not work as expected (i.e. this approach wouldn't work correctly in a Map or a Set).
You could try something like this:
data class Test(private val _value: Int) {
val value = _value
get(): Int {
return if (field < 0) 0 else field
}
}
assert(1 == Test(1).value)
assert(0 == Test(0).value)
assert(0 == Test(-1).value)
assert(1 == Test(1)._value) // Fail because _value is private
assert(0 == Test(0)._value) // Fail because _value is private
assert(0 == Test(-1)._value) // Fail because _value is private
In a data class you must to mark the primary constructor's parameters with either val or var.
I'm assigning the value of _value to value in order to use the desired name for the property.
I defined a custom accessor for the property with the logic you described.
The answer depends on what capabilities you actually use that data provides. #EPadron mentioned a nifty trick (improved version):
data class Test(private val _value: Int) {
val value: Int
get() = if (_value < 0) 0 else _value
}
That will works as expected, e.i it has one field, one getter, right equals, hashcode and component1. The catch is that toString and copy are weird:
println(Test(1)) // prints: Test(_value=1)
Test(1).copy(_value = 5) // <- weird naming
To fix the problem with toString you may redefine it by hands. I know of no way to fix the parameter naming but not to use data at all.
I have seen your answer, I agree that data classes are meant for holding data only, but sometimes we need to make somethings out of them.
Here is what i'm doing with my data class, I changed some properties from val to var, and overid them in the constructor.
like so:
data class Recording(
val id: Int = 0,
val createdAt: Date = Date(),
val path: String,
val deleted: Boolean = false,
var fileName: String = "",
val duration: Int = 0,
var format: String = " "
) {
init {
if (fileName.isEmpty())
fileName = path.substring(path.lastIndexOf('\\'))
if (format.isEmpty())
format = path.substring(path.lastIndexOf('.'))
}
fun asEntity(): rc {
return rc(id, createdAt, path, deleted, fileName, duration, format)
}
}
I know this is an old question but it seems nobody mentioned the possibility to make value private and writing custom getter like this:
data class Test(private val value: Int) {
fun getValue(): Int = if (value < 0) 0 else value
}
This should be perfectly valid as Kotlin will not generate default getter for private field.
But otherwise I definitely agree with spierce7 that data classes are for holding data and you should avoid hardcoding "business" logic there.
I found the following to be the best approach to achieve what you need without breaking equals and hashCode:
data class TestData(private var _value: Int) {
init {
_value = if (_value < 0) 0 else _value
}
val value: Int
get() = _value
}
// Test value
assert(1 == TestData(1).value)
assert(0 == TestData(-1).value)
assert(0 == TestData(0).value)
// Test copy()
assert(0 == TestData(-1).copy().value)
assert(0 == TestData(1).copy(-1).value)
assert(1 == TestData(-1).copy(1).value)
// Test toString()
assert("TestData(_value=1)" == TestData(1).toString())
assert("TestData(_value=0)" == TestData(-1).toString())
assert("TestData(_value=0)" == TestData(0).toString())
assert(TestData(0).toString() == TestData(-1).toString())
// Test equals
assert(TestData(0) == TestData(-1))
assert(TestData(0) == TestData(-1).copy())
assert(TestData(0) == TestData(1).copy(-1))
assert(TestData(1) == TestData(-1).copy(1))
// Test hashCode()
assert(TestData(0).hashCode() == TestData(-1).hashCode())
assert(TestData(1).hashCode() != TestData(-1).hashCode())
However,
First, note that _value is var, not val, but on the other hand, since it's private and data classes cannot be inherited from, it's fairly easy to make sure that it is not modified within the class.
Second, toString() produces a slightly different result than it would if _value was named value, but it's consistent and TestData(0).toString() == TestData(-1).toString().
Seems to be an old but interesting question.
Just want to contribute an option:
data class Test(#JvmField val value: Int){
fun getValue() = if(value<0) 0 else value
}
Now you can override getValue, and still have component1() working.
This seems to be one (among other) annoying drawbacks of Kotlin.
It seems that the only reasonable solution, which completely keeps backward compatibility of the class is to convert it into a regular class (not a "data" class), and implement by hand (with the aid of the IDE) the methods: hashCode(), equals(), toString(), copy() and componentN()
class Data3(i: Int)
{
var i: Int = i
override fun equals(other: Any?): Boolean
{
if (this === other) return true
if (other?.javaClass != javaClass) return false
other as Data3
if (i != other.i) return false
return true
}
override fun hashCode(): Int
{
return i
}
override fun toString(): String
{
return "Data3(i=$i)"
}
fun component1():Int = i
fun copy(i: Int = this.i): Data3
{
return Data3(i)
}
}
You can follow the Builder Pattern for this I think it'd be much better.
Here is an example:
data class Test(
// Fields:
val email: String,
val password: String
) {
// Builder(User):
class Builder(private val email: String) {
// Fields:
private lateinit var password: String
// Methods:
fun setPassword(password: String): Builder {
// Some operation like encrypting
this.password = password
// Returning:
return this
}
fun build(): Test = Test(email, password)
}
}