CodeBlanks Logo Icon CodeBlanks

Completing tasks

Learn to update task status with completeTask.

Completing tasks: completeTask and copy

To complete a task, the completeTask(title) method finds the task whose title matches and sets done to true. Because Task is a data class (immutable), we use copy(done = true) to make an updated copy and replace the slot in the list.

fun completeTask(title: String) {
    val i = tasks.indexOfFirst { it.title == title }
    if (i >= 0) {
        tasks[i] = tasks[i].copy(done = true)
    }
}

indexOfFirst { } gives the first index matching the condition, or -1. The i >= 0 check makes the update happen only if the task was found.

indexOfFirst and a missing task

indexOfFirst { condition } returns the index of the first element matching the condition; if none matches, it returns -1. This lets completeTask silently do nothing when called with a non-existent title.

val i = tasks.indexOfFirst { it.title == "Missing" }
// i = -1; the if (i >= 0) block does not run

This "silently skip" approach keeps the CLI from crashing when the user mistypes a title. You can also add a "task not found" message if you prefer.

Practice Add and call the completeTask method

Add a fun completeTask(title: String) method to TodoList: find with val i = tasks.indexOfFirst { it.title == title }, and inside if (i >= 0) do tasks[i] = tasks[i].copy(done = true). In main add two tasks, call completeTask("Homework"), and print with listTasks().

Starter code

Main.kt
fun main() {
    val list = TodoList()
    list.addTask("Shopping")
    list.addTask("Homework")
    // Complete "Homework" and print with listTasks
}

// The Task and TodoList classes stay as defined in the previous lesson.
// Add the completeTask method inside TodoList: find with indexOfFirst, update with copy.

Sample solution

Main.kt
fun main() {
    val list = TodoList()
    list.addTask("Shopping")
    list.addTask("Homework")
    list.completeTask("Homework")
    list.listTasks()
}

data class Task(val title: String, val done: Boolean = false) {
    fun format() = if (done) "[x] $title" else "[ ] $title"
}

class TodoList {
    val tasks = mutableListOf<Task>()
    fun addTask(title: String) {
        tasks.add(Task(title))
    }
    fun listTasks() {
        tasks.forEach { println(it.format()) }
    }
    fun completeTask(title: String) {
        val i = tasks.indexOfFirst { it.title == title }
        if (i >= 0) {
            tasks[i] = tasks[i].copy(done = true)
        }
    }
}

Expected output

[ ] Shopping
[x] Homework

Questions and answers

Review the lesson questions together with their answers. To test yourself, solve the lesson interactively.

1 Match expression to role

Term Meaning
completeTask(title) Completes the task
indexOfFirst { } Index of first match
copy(done = true) New copy, done = true
tasks[i] = ... List slot is updated

2 How does completeTask update a task?

  • Builds a new list
  • Makes a new Task with copy and replaces it Correct answer
  • Deletes the old Task
  • Sets the Task to null

Explanation: Since Task is immutable, we make a copy with copy and replace it.

3 Fill in the blank: update with copy

Question
tasks[i] = tasks[i].____(done = true)
Answer
tasks[i] = tasks[i].copy(done = true)

Explanation: tasks[i].copy(done = true) makes a new copy.

All lessons in Beginner