Part of Github Copilot with Kotlin

Kotlin and Copilot: Add a method to a class

Sandy LaneSandy Lane

Video: Kotlin and Copilot: Add a method to a class by Taught by Celeste AI - AI Coding Coach

Take the quiz on the full lesson page
Test what you've read · interactive walkthrough

Kotlin: Add a Method to a Class

class Person(val name: String) { fun greet() { println("Hello, $name!") } }. The class body holds methods; the constructor parameters become properties when prefixed val.

A small OOP puzzle: define a class with a property and a method, then call it. Demos Kotlin's primary-constructor + class-body shape.

The Copilot prompt

// A Person class with a greet() method
class Person(val name: String) {

Copilot generates:

class Person(val name: String) {
  fun greet() {
    println("Hello, my name is $name!")
  }
}

fun main() {
  val person = Person("Alice")
  person.greet()   // "Hello, my name is Alice!"
}

Walkthrough

1. Primary constructor. class Person(val name: String) — the parameter list is the primary constructor. val name makes it a property; without val/var, the parameter is only available inside the constructor (not as a property).

2. Method body. fun greet() is a regular function inside the class. It can read properties (name) without explicit this.

3. Instantiation. Person("Alice") calls the primary constructor. No new keyword in Kotlin.

4. Method call. person.greet() — same as any other function call, on the instance.

Class essentials

class Person(
  val name: String,         // public read-only property
  var age: Int,             // public mutable property
  private val id: Int,      // private read-only property
) {
  fun greet() = println("Hello, $name!")
  fun haveBirthday() { age++ }
  fun describe() = "$name (age $age, id $id)"
}

val alice = Person("Alice", 30, 1)
alice.haveBirthday()
println(alice.age)         // 31
println(alice.describe())  // "Alice (age 31, id 1)"
// alice.id  → compile error, id is private

val for read-only, var for mutable. private/protected/internal/public for visibility (default is public).

Adding a method

To "add a method," put a function in the class body:

class Person(val name: String) {
  fun greet() { println("Hello, $name!") }
  fun shout() { println("HEY, ${name.uppercase()}!") }
  fun whisper() { println("(psst, $name)") }
}

Three methods. Each can read properties; each is callable on instances.

Methods vs extension functions

You can also add methods outside the class via extensions:

class Person(val name: String)

fun Person.greet() {
  println("Hello, $name!")
}

val alice = Person("Alice")
alice.greet()   // works, looks like a member method

Difference:

  • Member function — defined inside the class. Has access to private members. Can be overridden in subclasses.
  • Extension function — defined outside. Static dispatch (no override). Can't access privates.

For data class and library-like types, members are preferred. For adding utility functions to types you don't own, extensions are the only option.

Single-expression methods

class Person(val name: String) {
  fun greet() = "Hello, $name!"
  fun isAdult(age: Int) = age >= 18
}

fun name(args) = expression is the single-expression form — no braces, no explicit return. Idiomatic for one-liners.

init blocks

For initialization logic that runs when the constructor is called:

class Person(val name: String, val age: Int) {
  init {
    require(age >= 0) { "Age must be non-negative" }
    require(name.isNotBlank()) { "Name must not be blank" }
  }

  init {
    println("Created Person: $name")
  }
}

init { ... } blocks run in declaration order during construction. Multiple init blocks are allowed.

Companion object for static members

class Person(val name: String) {
  companion object {
    const val DEFAULT_GREETING = "Hello"
    fun fromString(s: String): Person {
      val (name) = s.split(",")
      return Person(name.trim())
    }
  }
}

println(Person.DEFAULT_GREETING)
val p = Person.fromString("Alice, hi")

companion object holds class-level (static-like) members. Person.DEFAULT_GREETING and Person.fromString(...) work without an instance.

data class for value types

If your class is mostly data (with equals, hashCode, toString, copy), use data class:

data class Person(val name: String, val age: Int)

val a = Person("Alice", 30)
val b = Person("Alice", 30)
println(a == b)    // true (data class equality is structural)

val older = a.copy(age = 31)   // new instance with age changed
println(a)         // Person(name=Alice, age=30)

Auto-generates: - equals/hashCode based on properties. - toString showing all properties. - copy(...) for creating modified copies. - componentN() for destructuring (val (name, age) = person).

For most "record" types, data class is the right choice.

Common mistakes

Forgetting val/var on primary constructor params. Without it, the parameter isn't a property — person.name errors. With val, it's a public read-only property.

Using new. No new in Kotlin. Just Person(...).

Public-by-default surprise. Kotlin's default visibility is public. Java's is package-private. If you migrate Java code, you may unintentionally expose more.

Mixing class and data class. data class adds equals/hashCode/etc. — the difference is significant for collections (HashMap keys, etc.). Use data class for value types; plain class for entities with identity.

init order confusion. init blocks run in source order, interleaved with property initializers. val a = ...; init { ... }; val b = ... runs property a init, then the init block, then property b. Be careful with cross-references.

What's next

Episode 35: Create a Person class with just a name. A minimalist version — single property, no methods.

Recap

class Person(val name: String) { fun greet() = "Hello, $name!" }. Primary-constructor params with val/var become properties. Methods inside class body can read those properties. Single-expression methods: fun name(args) = expression. init { } blocks for construction logic. companion object for static-like members. data class for value types — auto-generates equals/hashCode/copy/toString.

Next episode: minimal Person class.

Ready? Take the quiz on the full lesson page →
Test what you've learned. Watch the lesson and try the interactive quiz on the same page.