5

Is it possible to create extension of final classes like String? Like in swift it is possible to add additional methods inside a extension of final class.

For an example - I would like to create a method in String extension which will tell me String have valid length for password.

 val password : String = mEdtPassword!!.getText().toString()

 // how to define haveValidLength method in extension
 val isValid : Boolean = password.haveValidLength()

Note - That example is just for a sake to understand usability of extension, not a real scenario.

Rahul
  • 10,457
  • 4
  • 35
  • 55

3 Answers3

6

yes, you can. Kotin extension method provides the ability to extend a class with new functionality without having to inherit from the class or use any type of design pattern such as Decorator.

Below is an extension method for a String:

//  v--- the extension method receiver type
fun String.at(value: Int) = this[value]

And the extension method code generated as Java below:

public static char at(String receiver, int value){
    return receiver.charAt(value);
}

So an extension method in Kotlin is using delegation rather than inheritance.

Then you can calling an extension method like as its member function as below:

println("bar".at(1))//println 'a'

You also can write an extension method for the existing extension function, for example:

fun String.substring(value: Int): String = TODO()

//    v--- throws exception rather than return "ar"
"bar".substring(1)

But you can't write an extension method for the existing member function, for example:

operator fun String.get(value: Int): Char = TODO()

//   v--- return 'a' rather than throws an Exception
val second = "bar"[1]
holi-java
  • 29,655
  • 7
  • 72
  • 83
  • Thank you for your response, I am thinking to add some additional methods rather than updating existing ones. Is it possible? – Rahul Jul 22 '17 at 13:01
  • @Rasi I don't updating existing `at`. `String` has no `at` method. the code above just an example, sir. – holi-java Jul 22 '17 at 13:03
  • @Rasi Hi, I have added a detailed explaination of the exntension method, you can see it as further. – holi-java Jul 22 '17 at 13:25
  • I tried to answer at a basic level which can help beginners like me. Please check and suggest Edit if needed. Thanks again! – Rahul Jul 22 '17 at 13:32
  • You cannot create an extension for an existing member function. The `substring` in your example is actually an extension itself in Kotlin, so you can choose which one you to import. If it were a member function you couldn't use your own extension with the same name as it is 'shadowed' by the real function. This is also explained in the [documentation](https://kotlinlang.org/docs/reference/extensions.html#extensions-are-resolved-statically) – RobCo Jul 22 '17 at 16:18
  • @RobCo hi, extension function has its own scope like as [top-level function scopes](https://stackoverflow.com/questions/44912705/kotlin-top-level-function-scopes-shadowing/44912960#44912960). having you copy the code and test it yet? – holi-java Jul 22 '17 at 16:18
  • Yes, it only works because all methods on String are defined as extensions in the framework. You can't 'override' an existing member function function as the answer suggests. For example try with File.getName() – RobCo Jul 22 '17 at 16:27
  • Well you're not wrong, and many methods in Kotlin lib are extensions so it still applies, I just found the wording a bit misleading. +1 – RobCo Jul 22 '17 at 16:31
  • Hello. So based on your explanation. If I have a final subclass of Recyclerview. And I want to override the function of dispatchTouchEvent which it hesitates from ViewGroup. This is also impossible right? – tainy Sep 01 '21 at 20:43
1

Trying to add more detail, this answer might be helpful for someone.

Yes we can add additional methods to final classes like String. For an example I would like to add one method in String which will tell me that my String have valid number of characters for password or not.

So what I have to do is, I have ti create a below function which can be written in same class or at different separate class file.

    fun String.hasValidPassword() : Boolean {

 // Even no need to send string from outside, use 'this' for reference of a String

     return !TextUtils.isEmpty(this) && this.length > 6
    }

And now from anywhere call

    val isValid : Boolean = password.haveValidLength()

Suggestion

If your application just has a single password validation, then there is no problem.

However, I don't suggest you write such a extension method hasValidPassword if the application has more than one validation. since the extension method is satically, you can't change your hasValidPassword in runtime. So if you want to change the validation in runtime, you should using a function instead, for example:

class PasswordRepository(private val validate:(String)->Boolean){
    fun save(value:String){
        if(validate(value)){
            //TODO persist the password
        }
    }
}

val permitAll = PasswordRepository {true}
val denyAll = PasswordRepository {false}

permitAll.save("it will be persisted")
denyAll.save("it will not be persisted")

In other words, the extension method above violates Single Responsibility Principle, it does validation & string operations.

holi-java
  • 29,655
  • 7
  • 72
  • 83
Rahul
  • 10,457
  • 4
  • 35
  • 55
  • Hi, How about it now? do you having any confusing? I'm not good at english, I wish you can understand it. – holi-java Jul 22 '17 at 13:50
  • Thanks for update. My intention was just to show, how to add additional methods in final classes. No intention to use any kind of that method. It was random example. – Rahul Jul 22 '17 at 14:04
  • well. I have up-vote it since it is right about your intention. – holi-java Jul 22 '17 at 14:05
0

You can do that with extension functions in Kotlin. With extensions, you are able to add extra functionality to a class that you do or do not have access to; for example a legacy code base. In the example given in the Kotlin docs here, swap was added to MutableList<Int> which doesn't have swap originally. A this keyword is used that refers to the object that the swap functionality will operate on. In the example below, this refers to testList

val testList = mutableListOf(1, 2, 3)
testList.swap(0, 2)
Alf Moh
  • 7,159
  • 5
  • 41
  • 50