42

In other languages like Swift, there is the possibility of creating a function extension that adds a new constructor.

Something like this:

// base class
class Whatever() {
    ...
}

// constructor method extension
fun Whatever.constructor(potato: String) {
    setPotato(potato)
}

fun main(args: Array<String>) {
    println(Whatever("holi"))
}

Are there any means to do this in Kotlin?

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
Aracem
  • 7,227
  • 4
  • 35
  • 72

6 Answers6

51

Seems that there are not an official "function extension for constructors" but you can create a package-method that imitates a constructor

class Foo() {
    ...
}

fun Foo(stuff: Int): Foo = Foo().apply {setStuff(stuff)}

fun main(args: Array<String>){
    println(Foo(123))
}
Aracem
  • 7,227
  • 4
  • 35
  • 72
  • 3
    This does not imitate the constructor, it is the factory pattern :) – Willi Mentzel Oct 05 '17 at 10:05
  • 9
    You are right but this has a difference, you do not need to call Factory.foo(123). Sugar code anyway – Aracem Oct 05 '17 at 10:08
  • 10
    @WilliMentzel It imitates a constructor for the clients: they call it the same way they would a constructor and don't need to know which it is. – Alexey Romanov Oct 05 '17 at 12:02
  • 1
    @AlexeyRomanov I don't think this is good style to do this. A function's name should start lower-case. this is just a hack in my eyes. – Willi Mentzel Oct 05 '17 at 12:09
  • 2
    @WilliMentzel For this specific use I think it's perfectly fine. Of course, that's just my opinion. – Alexey Romanov Oct 05 '17 at 12:20
  • 5
    While this will work to mimic a constructor for the users, doing so has downsides as well: https://stackoverflow.com/questions/34751897/is-naming-a-function-same-as-an-existing-class-should-be-avoided-in-kotlin-why – hotkey Oct 05 '17 at 12:23
17

Not like in Swift, because:

Extensions are resolved statically. Extensions do not actually modify classes they extend. By defining an extension, you do not insert new members into a class, but merely make new functions callable with the dot-notation on variables of this type. (Source)


If a companion object is defined in your target class, go with s1m0nw1's approach. The advantage is that you can call the extension function without an instance (statically) of the target class.


If not, use a classic Factory Pattern:

class Fruit(var name: String = "") {
}

class FruitFactory {
    companion object {
        fun create(name: String): Fruit {
            return Fruit().apply {
                this.name = "Tasty $name"
            }
         }
    }
}

fun main(args: Array<String>) {
    val orange = Fruit("Orange")
    println(orange.name)

    val apple = FruitFactory.create("Apple")
    println(apple.name)
}

You can extend the Factory as you wish with further constructors either nested or as extension functions.

Output:

Orange
Tasty Apple

Willi Mentzel
  • 27,862
  • 20
  • 113
  • 121
11

You can't do this. What you can do though: Extend the companion object of a class with a factory method:

// base class
class Whatever() {
    companion object {

    }

}

// factory extension
fun Whatever.Companion.withPotato(potato: String) {
    //setPotato(potato)
}

fun main(args: Array<String>) {
    println(Whatever.withPotato("holi"))
}

The only problem: A companion object has to be existent to do this.

s1m0nw1
  • 76,759
  • 17
  • 167
  • 196
5

Based on @s1m0nw1 solution, I can adjust it to be more like the OP wanted by overriding operator invoke.

// base class
class Whatever() {
    companion object {
        fun setPotato(potato: String)
    }
}

operator fun Whatever.Companion.invoke(potato: String) {
    setPotato(potato)
}

fun main(args: Array<String>) {
    println(Whatever("holi"))
}

Keep in mind that it still needs companion object inside base class. If you can't edit the source of base class (in case of kotlin framework class or third party class), and if it already has companion object that you want to add your new method to, you can always use an extension function:

fun Int.Companion.setPotato(potato: String) {
    // ...
}
koto
  • 720
  • 2
  • 9
  • 29
1

Something that is very common in Kotlin is to create a regular function with the constructor-like arguments and return an appropriate instance. The function name is the camelCase version of the class name, often with the 'Of' suffix.

Example functions:

  • listOf
  • mutableListOf
  • arrayListOf
  • emptyList
  • mutableStateOf ` etc.

So a Kotlin "idiomatic" way to do what you want would be:

// base class
class Whatever() {
    ...
}

// "constructor" method
fun whateverOf(potato: String) = Whatever().apply {
    setPotato(potato)
}

fun main(args: Array<String>) {
    println(whateverOf("holi"))
}
Lior
  • 7,845
  • 2
  • 34
  • 34
0

Another alternative is to just declare an extension function on the argument (or the first one if there are many):

// base class
class Whatever() {
    ...
}

// extension
fun String.toWhatever() = Whatever().apply { setPotato(this) }

fun main(args: Array<String>) {
    println("holi".toWhatever())
}

The pros:

  • You avoid the hassle of declaring an empty Companion object
  • Still possible when the Whatever class doesn't have a Companion AND is not yours, so you couldn't add a Companion even if you wanted
  • Compact and idiomatic approach
acdcjunior
  • 132,397
  • 37
  • 331
  • 304