The Programmers Guide To Kotlin - Data Classes
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:

USA and World     Amazon.com
Canada            Amazon.ca

UK                Amazon.co.uk
France            Amazon.fr
Germany           Amazon.de
Spain             Amazon.es
Italy             Amazon.it

 

 

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 (Coming soon!)
  8. Generics
  9. Collections, Iterators, Sequences & Ranges
  10. Advanced functions 
  11. Anonymous, Lamdas & Inline Functions
  12. Data classes, enums and destructuring
    Extract 1 Data Classes  **NEW!**
  13. Exceptions, Annotations & Reflection
  14. Working with Java

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


Facebook Open Sources RacerD For Android Race Detection
23/10/2017

It is a hardly discussed problem, but Android is a tough platform to use with concurrent programming. As a result most apps don't use it to its full potential. Facebook has now gifted you a tool that  [ ... ]



Which Languages Are Bug Prone
04/10/2017

A large-scale study of the effect of programming languages on software quality is reported in this month's Communications of the ACM. Here we report some of its major findings relating to the pre [ ... ]


More News

 
 

 

blog comments powered by Disqus

 <ASIN:1871962536>



Last Updated ( Monday, 09 October 2017 )
 
 

   
Banner
RSS feed of all content
I Programmer - full contents
Copyright © 2017 i-programmer.info. All Rights Reserved.
Joomla! is Free Software released under the GNU/GPL License.