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
  8. Generics
            Extract Basic Generics
            Extract Covariance & Contravariance
  9. Collections, Iterators, Sequences & Ranges
            Extract Iterators & Sequences
  10. Advanced functions 
  11. Anonymous, Lamdas & Inline Functions
            Extract Annoymous and Lambda Functions  
  12. Data classes, enums and destructuring
            Extract  Data Classes
            Extract 
         Delegated Properties 
  13. Exceptions, Annotations & Reflection
            Extract Annotation & Reflection 
  14. Working with Java
            Extract Using Swing  **NEW!**

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, FacebookGoogle+ or Linkedin.

 

Banner


End Manual Data Entry in Excel - Thanks AI!
04/03/2019

Manual entry of data to a spreadsheet is, or rather was, a chore. Now it is even more something that belongs to the past. Microsoft has rolled out another AI-powered feature to Excel - that of inserti [ ... ]



AI Takes Control Of A Wind Farm
27/02/2019

No not a post-apocalypse scenario - Google's DeepMind helps make a wind farm 20% more valuable by predicting when the wind will blow.


More News

Python

 



 

Comments




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

 <ASIN:1871962536>



Last Updated ( Monday, 09 October 2017 )