Extension Function vs Member Function in Kotlin: Key Differences and Usage
member function is defined inside a class and has access to its private members, while an extension function is defined outside the class and adds functionality without modifying the original class. Extension functions cannot access private members but allow adding new behavior to existing classes easily.Quick Comparison
This table summarizes the main differences between member functions and extension functions in Kotlin.
| Aspect | Member Function | Extension Function |
|---|---|---|
| Definition | Function declared inside a class | Function declared outside a class with receiver type |
| Access to private members | Yes, can access private and protected members | No, cannot access private or protected members |
| Modification of original class | Modifies class by adding function | Does not modify class, adds functionality externally |
| Dispatch mechanism | Virtual dispatch (polymorphic) | Static dispatch (resolved at compile time) |
| Use case | Core behavior of class | Add functionality to classes without inheritance or source change |
| Syntax | fun functionName() { } inside class body | fun ClassName.functionName() { } outside class body |
Key Differences
Member functions are part of the class definition. They have full access to the class's internal state, including private and protected members. This means they can manipulate the class's data directly and participate in polymorphism through overriding.
Extension functions are declared outside the class using a special syntax that specifies the receiver type. They allow you to add new functions to existing classes without changing their source code or using inheritance. However, they cannot access private or protected members of the class because they are not actually part of the class.
Another important difference is how Kotlin resolves calls: member functions use virtual dispatch, meaning the actual function called depends on the runtime type of the object. Extension functions use static dispatch, so the function called depends on the compile-time type of the variable, which can lead to different behavior in inheritance scenarios.
Code Comparison
Here is an example showing a member function inside a class that returns a greeting message.
class Person(val name: String) { fun greet(): String { return "Hello, $name!" } } fun main() { val person = Person("Alice") println(person.greet()) }
Extension Function Equivalent
The same greeting functionality can be added as an extension function outside the Person class.
class Person(val name: String) fun Person.greet(): String { return "Hello, $name!" } fun main() { val person = Person("Alice") println(person.greet()) }
When to Use Which
Choose member functions when you control the class source and need to access or modify its internal state or want to use polymorphism. They are best for core behaviors tightly coupled with the class.
Choose extension functions when you want to add utility or helper functions to classes you do not own or cannot modify, or when you want to keep your code modular and clean without inheritance. They are ideal for adding functionality without changing existing code.