Home > Enterprise >  Kotlin : function extension inside companion object
Kotlin : function extension inside companion object

Time:06-08

In Kotlin language, what does this syntax do and how does it work ?

class ClassName1 {
    companion object {          
        fun ClassName2.funName()=""         
    } 
}

CodePudding user response:

There are multiple things at play here:

  • extension functions: they allow to use the function as if it were part of the receiver type (the type on the left of the function name)
  • extension functions used as members: extension functions that can be used on their receiver (known as extension receiver) only when the enclosing class (the dispatch receiver) is in scope
  • companion objects: a special object that is associated to a class and can be referenced by just using the class name

Declaring a member extension function inside a companion object might be useful for different things.

For instance, such function can be used within the class as if the extension function was declared as a class member but outside the companion. Some people prefer to put them in the companion object to make it clear that they don't depend on the state of said class (like a Java static function):

class ClassName1 {

    fun method(): String {
        val something = ClassName2()
        return something.funName()
    }

    companion object {          
        fun ClassName2.funName() = ""         
    } 
}

Such use doesn't require the function to be public, though.

Another way to use this would be by using the companion object as a sort of scope:

val something = ClassName2()
with(ClassName1) { // this: ClassName1.Companion
   something.funName() // brought in scope by ClassName1's companion
}

Or directly if you import the function from the companion:

import ClassName1.Companion.funName

val something = ClassName2()
something.funName()

Such pattern is used for instance for Duration.Compaion to define extensions on number types (those are extension properties but it's the same idea): https://github.com/JetBrains/kotlin/blob/6a670dc5f38fc73eb01d754d8f7c158ae0176ceb/libraries/stdlib/src/kotlin/time/Duration.kt#L71

CodePudding user response:

This is a weird syntax. One example to use this can be:

import ClassName1.Companion.funName

class ClassName1 {
    companion object {
        fun ClassName2.funName() = ""
    }
}

class ClassName2

fun main() {
    ClassName2().funName()
}

Here I had to import funName from Class1.Companion in order to call it. There's no easy way to call this function.

If you don't have past experience with extension functions, you can take a look at the decompiled bytecode to see what's happening under the hood:

public final class ClassName2 {
}

public final class ClassName1 {
   @NotNull
   public static final ClassName1.Companion Companion = new ClassName1.Companion((DefaultConstructorMarker)null);

   public static final class Companion {
      @NotNull
      public final String funName(@NotNull ClassName2 $this$funName) {
         return "";
      }

      private Companion() {
      }

      public Companion(DefaultConstructorMarker $constructor_marker) {
         this();
      }
   }
}

public final class YourFileNameKt {
   public static final void main() {
      ClassName1.Companion.funName(new ClassName2());
   }
}

funName is a function inside static Companion class declared inside ClassName1. It receives a ClassName2 object as a parameter (this is how extension functions work, nothing special here).

But I would say that this type of declaration is very confusing. It would be better if you could provide more info on how this is being used in your case. Passing a ClassName2 object directly in the function seems to be a much cleaner approach here.

  • Related