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

Now Available as a Print Book

cover

You can buy it from: Amazon

Contents

Some Chapters Already Available On The Web

  1. What makes Kotlin Special (Book Only)
  2. The Basics: Variables, Primitive Types and Functions
  3. Control
  4. Strings and Arrays
  5. The Class & The Object
  6. Inheritance
  7. The Type Hierarchy 
            Extract  Type and its problems
            Extract  Smart Casts **NEW!**
  8.  
  9. Generics
            Extract Basic Generics
            Extract Covariance & Contravariance
  10. Collections, Iterators, Sequences & Ranges
            Extract Iterators & Sequences
  11. Advanced functions 
  12. Anonymous, Lamdas & Inline Functions
            Extract Annoymous and Lambda Functions  
  13. Data classes, enums and destructuring
            Extract  Data Classes
            Extract 
         Delegated Properties 
  14. Exceptions, Annotations & Reflection
            Extract Annotation & Reflection 
  15. Working with Java
            Extract Using Swing  

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


Microsoft Graph Data Connect Now Generally Available
16/05/2019

Microsoft Graph data connect is now generally available. The announcement was made at this year's Build conference. Graph is a unified programmability model and APIs that can be used to access data wi [ ... ]



Microsoft Updates PWABuilder
29/04/2019

Microsoft has updated PWABuilder, its open source tool for converting Web applications to Progressive Web Apps (PWAs). which act more like native desktop/mobile apps with the help of several technolog [ ... ]


More News

Python

 



 

Comments




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

 <ASIN:1871962536>



Last Updated ( Monday, 09 October 2017 )