The Programmers Guide To Kotlin - Data Classes
Written by Mike James   
Monday, 09 October 2017
Article Index
The Programmers Guide To Kotlin - Data Classes
Equals, Destructuring

Custom Equals

The big problem with equals is that the default implementation inherited from Any only compares references. That is by default equals and hence === is the same as ==.

Many standard classes and all primitive data types override equals to give you the result you would expect but not all.

For example, for arrays the equals method is still the one inherited from Any and hence two arrays are considered equal only if the variables reference the same array object. This is sometimes what you need, but if you really want to discover if two distinct arrays are equal based on their content then you have to use:

a contentEquals b

This is an infix operator which compares elements of each array and returns true if they are all equal. This works unless one of the element is itself an array when the elements are compared referentially. If you want elements that are themselves arrays to be compared structurally you need to use:

a contentDeepEquals b

this compares any elements that might be arrays structurally at any level in the structure. Notice that there are deep versions of hashCode and toString.

Arrays indicate the basic problem with defining equality for general classes. Do you implement a shallow equality that simply compares properties that happen to be objects referentially or do you do a deep compare that compares such objects structurally and so on.

In the case of data classes, List, Map and Set, Kotlin performs a shallow structural comparison. For an array the order of the elements is important. An array with the same values as another but in a different order is not equal. If two maps have the same set of key/value pairs then they are equal irrespective of the order they were added. For two sets to be equal they simply have have the same elements in any order. 

The notion of what constitutes equality is a very varied idea. For example is 123 equal to "123"? In most case you need to check any inherited or standard implementation of equals you may have, and see that it fits in with what you mean by equality. You also need to be ready to implement your own equals and hashCode methods.

Destructuring

Destructuring is a sophisticated sounding name for a very simple idea. Sometimes you have a data structure with a number of elements or properties and you want to unpack these into a set of standalone variables. 

For example if we have a data class:

data class MyDataClass(var name:String,var age:Int)

Then we can create an instance and use destructuring to pack the data into separate variables:

var myDataObject=MyDataClass("Mickey",89)
var (myName,myAge) = myDataObject
println(myName)
println(myAge)

The destructuring assignment:

var (myName,myAge) = myDataObject

is converted into:

var myName = myDataObject.component1()
var myAge = myDataObject.component2()

For a data object the operator methods component1, component2 and so on are automatically generated. This is the reason why if you take the data modifier from the start of the declaration you will get an error message as the class no longer has componentN methods.

Of course you can add them manually:

class MyDataClass(var name:String,var age:Int){
   operator fun component1()=name
   operator fun component2()=age
}

In fact any class that has componentN operator methods can be used in a destructuring operation.

As well as assignment destructuring can be used in:

for loops

For example

val myList=listOf(MyDataClass("Mickey",89),
                        MyDataClass("Minnie",88))
for ((name,age) in myList){
     println(name)
     println(age)
}

As long as each element that the iterator returns supports destructuring, you can use this sort of for loop.

data class to allow a function to seem to return multiple values

For example:

fun myFavouriteMouse():MyDataClass{
     return MyDataClass("Mickey",89)
 }

and you can now write:

var (myName,myAge)=myFavouriteMouse()

which looks as if myFavouriteMouse returns multiple values in the same way that you can in Python.

If you don't want to make use of a destructure value you can use an underscore to leave it out:

var (_,myAge)=myFavouriteMouse()

Finally, you can use destructuring in parameters of lambdas as long as the parameter type has componentN operator functions. Notice that this makes adding an extra set of parenthesis in a lambda an error. That is:

{ a,b-> statements that use a and b}
{(a,b)-> statements that use a and b}

are different in that the second one accepts a single parameter that can be destructured to give a and b.

For example:

 val myLambda= {(name,age):MyDataClass->
       println(name)
       println(age)
    }

This looks like a lambda that would accept two parameters, but because of destructuring it accepts a single instance of MyDataClass:

val myDataObject=MyDataClass("Mickey",89) myLambda(myDataObject)

This works with any class that supports componentN operator methods.

 

Programmer's Guide To Kotlin Third Edition

kotlin3e360

You can buy it from: Amazon

Contents

  1. What makes Kotlin Special
  2. The Basics:Variables,Primitive Types and Functions 
  3. Control
         Extract: If and When 
  4. Strings and Arrays
  5. The Class & The Object ***NEW!
  6. Inheritance
  7. The Type Hierarchy
  8. Generics
  9. Collections, Iterators, Sequences & Ranges
        Extract: Iterators & Sequences 
  10. Advanced functions 
  11. Anonymous, Lamdas & Inline Functions
  12. Data classes, enums and destructuring
        Extract: Destructuring 
  13. Exceptions, Annotations & Reflection
  14. Coroutines
        Extract: Coroutines 
  15. Working with Java
        Extract: Using Swing
  16. Compose Multiplatform
        Extract: Compose Layout 

<ASIN:B0D8H4N8SK>

kotlinlogo

To be informed about new articles on I Programmer, sign up for our weekly newsletter, subscribe to the RSS feed and follow us on Twitter, Facebook or Linkedin.

 

Banner


A Turing Machine In LEGO
06/10/2024

A Turing Machine is one of those abstract ideas that is much easier to undertand if you can see it working. Now there's a proposal on the LEGO Ideas site for a Working Turing Machine. Lend it your sup [ ... ]



52nd Mersenne Prime Found
27/10/2024

It has been nearly six years since the last Mersenne prime was discovered. Now, at last, we have Mersenne prime number 52 and it has 41,024,320 digits!


More News

espbook

 

Comments




or email your comment to: comments@i-programmer.info

 <ASIN:1871962536>



Last Updated ( Monday, 09 October 2017 )