Home Android & Kotlin Books Kotlin Apprentice

14
Methods Written by Victoria Gonda

Heads up... You're reading this book for free, with parts of this chapter shown beyond this point as scrambled text.

You can unlock the rest of this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

In the previous chapter, you learned about properties, which are constants and variables that are part of classes and objects. Methods, as you’ve already seen, are merely functions that reside inside a class or object.

In this chapter, you’ll take a closer look at methods. As with properties, you’ll begin to design more complex classes and objects. So, open the starter project and jump right in!

Method refresher

Consider ArrayList.removeAt(). It pops the item at a given index off an instance of an array list:

val numbers = arrayListOf(1, 2, 3)
numbers.removeAt(numbers.lastIndex)
println(numbers) // > [1, 2]

Methods like removeAt() help you control the data in the array list.

Comparing methods to getters and setters

With custom accessors, you saw in the last chapter that you could run code from inside a class within a property definition. That sounds a lot like a method. What’s the difference? It really comes down to a matter of style, but there are a few helpful thoughts to help you decide.

Turning a function into a method

To explore methods, you will create a simple model for dates called SimpleDate. Be aware that the various Kotlin platforms, such as the JVM and JS, contain production-ready Date classes that correctly handle many of the subtle intricacies of dealing with dates and times.

// 1
val months = arrayOf(
    "January", "February", "March",
    "April", "May", "June",
    "July", "August", "September",
    "October", "November", "December"
)

// 2
class SimpleDate1(var month: String)

// 3
fun monthsUntilWinterBreak(from: SimpleDate1): Int {
  return months.indexOf("December") - months.indexOf(from.month)
}
class SimpleDate2(var month: String) {
  fun monthsUntilWinterBreak(from: SimpleDate2): Int {
    return months.indexOf("December") - months.indexOf(from.month)
  }
}

val date2 = SimpleDate2("October")
println(date2.monthsUntilWinterBreak(date2)) // > 2
date.monthsUntilWinterBreak() // Error!

Introducing this

A class definition is like a blueprint, whereas an instance is a real object. To access the value of an instance, you use the keyword this inside the class.

// 1
fun monthsUntilWinterBreak(): Int {
  // 2
  return months.indexOf("December") - months.indexOf(this.month)
}
val date3 = SimpleDate3("September")
date3.monthsUntilWinterBreak() // 3
return months.indexOf("December") - months.indexOf(month)

Mini-exercise

Since monthsUntilWinterBreak() returns a single value and there’s not much calculation involved, transform the method into a property with a customer getter.

Object methods

Like classes, Kotlin objects defined with the object keyword can have member functions that refer to the object itself.

class MyMath {
  // 1
  companion object {
    fun factorial(number: Int): Int {
      // 2
      return (1..number).fold(1) { a, b -> a * b }
    }
  }
}

// 3
MyMath.factorial(6) // 720

Mini-exercise

Add a method to the MyMath class that calculates the n-th triangle number. It will be similar to the factorial formula, except instead of multiplying the numbers, you add them.

Extension methods

Sometimes you want to add functionality to a class but don’t want to muddy up the original definition. And sometimes you can’t add the functionality because you don’t have access to the source code. Just as for properties, it is possible to augment an existing class or object (even one you do not have the source code for) by adding methods to it.

fun SimpleDate.monthsUntilSummerBreak(): Int {
  val monthIndex = months.indexOf(month)
  return if (monthIndex in 0..months.indexOf("June")) {
    months.indexOf("June") - months.indexOf(month)
  } else if (monthIndex in
      months.indexOf("June")..months.indexOf("August")) {
    0
  } else {
    months.indexOf("June") + (12 - months.indexOf(month))
  }
}
val date = SimpleDate()
date.month = "December"
println(date.monthsUntilSummerBreak()) // > 6
fun Int.abs(): Int {
  return if (this < 0) -this else this
}

println(4.abs())    // > 4
println((-4).abs()) // > 4

Companion object extensions

If your class has a companion object, you can add extension methods to it by using the implicit companion object name Companion, or by using the custom name if the companion object has one.

fun MyMath.Companion.primeFactors(value: Int): List<Int> {
  // 1
  var remainingValue = value
  // 2
  var testFactor = 2
  val primes = mutableListOf<Int>()
  // 3
  while (testFactor * testFactor <= remainingValue) {
    if (remainingValue % testFactor == 0) {
      primes.add(testFactor)
      remainingValue /= testFactor
    } else {
      testFactor += 1
    }
  }

  if (remainingValue > 1) {
    primes.add(remainingValue)
  }

  return primes
}
MyMath.primeFactors(81) // [3, 3, 3, 3]

Challenges

As you work through these challenges, remember you can look at the solutions for this chapter at any time for a hint or to check your work.

import kotlin.math.PI

class Circle(var radius: Double = 0.0) {
 val area: Double
   get() {
     return PI * radius * radius
   }
}
val months = arrayOf(
   "January", "February", "March",
   "April", "May", "June",
   "July", "August", "September",
   "October", "November", "December"
)

class SimpleDate(var month: String, var day: Int = 0) {
 fun advance() {
   day += 1
 }
}

var date = SimpleDate(month = "December", day = 31)
date.advance()
date.month // December; should be January!
date.day // 32; should be 1!

Key points

  • Methods are behaviors that extend the functionality of a class.
  • A typical method is a function defined inside of a class or object.
  • A method can access the value of an instance by using the keyword this.
  • Companion object methods add behavior to a class instead of the instances of that class. To define a companion object method, you add a function in the class companion object block.
  • You can augment an existing class definition and add methods to it using extension methods.

Where to go from here?

Methods and properties are the things that make up your classes, instances, and objects. Learning about them as you have these last two chapters is important since you’ll use them all the time in Kotlin.

Have a technical question? Want to report a bug? You can ask questions and report bugs to the book authors in our official book forum here.

Have feedback to share about the online reading experience? If you have feedback about the UI, UX, highlighting, or other features of our online readers, you can send them to the design team with the form below:

© 2021 Razeware LLC

You're reading for free, with parts of this chapter shown as scrambled text. Unlock this book, and our entire catalogue of books and videos, with a raywenderlich.com Professional subscription.

Unlock Now

To highlight or take notes, you’ll need to own this book in a subscription or purchased by itself.