I have learned that Open Close Principle is allowing extension to classes and restricting from modification. So in Kotlin, when we use extension function
Are we extending a class
Or are we modifying a class
Can extension functions in kotlin be an example for Open/Close Principle?
I assume extension means to apply inheritance and modification means to add or change code of existing class.
Thanks
The extenstion function is designed for situations where you want to add a function to a built-in or third-party class. You cannot do this by default because built-in functions are not modifiable.
An example implementation to add a toUnsigned method to the built-in Byte class:
fun Byte.toUnsigned(): Int {
return if (this < 0) this + 256 else this.toInt()
}
As Byte is a built-in class you cannot modify it directly. However, you can define an extension function as per above code. You can then call the extension function in the following way:
val x: Byte = -1
println(x.toUnsigned()) // Prints 255
Keep in mind that this is just syntactic sugar - you're not actually modifying the class or its instances. Therefore, you have to import an extension function/property wherever you want to use it (since it isn't carried along with the instances of the class).
Source : https://kotlinlang.org/docs/tutorials/kotlin-for-py/extension-functionsproperties.html
'Extension' in the context of the Open Closed Principle usually does not mean inheritance, it means somehow extending the class with new functionality. 'Modification' does refer to changing the code of the class, as you say.
The extension facility of Kotlin allows you to add a method to a class without editing the code of the class. This is perfectly in keeping with the Open Closed Principle -- the class is extended with new functionality without the class itself being changed.
Related
I've been playing recently with KSP and have managed to develop interesting capabilities (such as automatic recyclerview and view holder generators based on their layout id), and so far all is well.
However, I am now trying to do something different than creating files based on the annotations I design. Instead of creating files, I would only want to populate a list with the classes/objects annotated by me.
Example:
ClassA.kt
#MyAnnotation
class ClassA(context: Context): SomeBaseClass(context) {
override fun baseClassFunction() {
// custom code goes here
}
}
ClassB.kt
#MyAnnotation
class ClassB(context: Context): SomeBaseClass(context) {
override fun baseClassFunction() {
// custom code goes here
}
}
MyListAgregator.kt
object MyListAgregator {
const val classList: List<SomeBaseClass> = mutableListOf()
}
Where my custom KSP would do the following
Collect all classes/objects (the usual) that are annotated by my
#MyAnnotation
Create an instance of them with the appropriate
parameters (in this case just a context)
Add each one to the classList in the MyListAgregator
I can always get to the point of the class collection (step 1) but the rest is a complete mystery to me, and feels like KSP always expects to create code, not execute it? Perhaps I am incorrect on the later one, but I could not find anything related to that explained in the available documentation.
Another alternative I considered, but would rather avoid out of concern for any negative hit (performance, for example) is to actually modify that MyListAgregator file directly to include all the instances in the list, as if I had written them myself. However, I would still prefer to go with the previous option instead if it is at all possible.
First, you need to establish a ruleset that will be applied to the classes annotated with your annotation (symbol in KSP glossary). For example, they must contain one argument, that argument must be a member property and of type Context and must be subclass of SomeBaseClass. I suggest first look up for correct inheritance then look up for argument count and type.
You are still within reading and exploring all files with this symbol. Filtering based on this ruleset you will land with a set of classes at point 2.
Here, KSP can provide you with the interface to generate your code. However, KSP will not let you edit the source file, but generate new one based on your conditions. Here you have to write your implementation for the overriden function, by visiting it
You can preserve the output (newly generated classes at step 2) and generate your MyListAggregator object.
Recently at my company a debate started after reviewing a different approach for writing heavy duty classes.
A big Java class holding component specific logic (no standard OOP principles made sense) had to be rewritten in Kotlin. The solution provided was splitting the logic in categories and the categories into separate files with internal extension functions to the main class.
Example:
Main.kt
class BigClass {
// internal fields exposed to the extension functions in different files
// Some main logic here
}
BusinessLogic.kt
internal fun BigClass.handleBussinessCase() {
// Complex business logic handled here accessing the exposed internal fields from BigClass
}
What are your thoughts on this? I haven't seen it used anywhere maybe for a good reason, but the alternative of thousand lines classes seems worse.
You have to consider that an extension function is nothing more than a function with an implicit first parameter which is referenced with this.
So in your case you'd have something like:
internal fun handleBussinessCase(ref: BigClass)
which would translate to Java as:
static void handleBussinessCase(BigClass ref)
But this could be assumed to be a delegate pattern, which could be encapsulated much cleaner in Kotlin as well.
Since the properties have to be internal anyhow, you could just inject these as a data class into smaller use-cases. If you define an interface around these (which would make the properties public though), you could create a delegate pattern with it and still reference each property with this in your implementation.
Here are some thoughts on making extension functions for the class:
It will be a utility function that will operate with the object you're extending, it will not be an object function, meaning that it will have access to only public methods and properties;
If you're planning to use class that being extended in unit tests, these methods (extensions) will be harder to mock;
Most likely they wont behave as you expect when used with inherited objects.
Maybe I missed something, so please read more about extensions here.
ScreenDef is a class, I add a function setDevice for the class, which one is correct between Code A and Code B? why?
I think that Code B is correct, right?
Code C
data class ScreenDef(
val brightness: Int
): DeviceDef
class ScreenHelper(val mContext: Context) {
fun setScreen(aScreenDef: ScreenDef){
}
}
Code A
fun ScreenDef.setDevice(mContext: Context) {
ScreenHelper(mContext).setScreen(this)
}
Code B
fun ScreenDef.setDevice(mContext: Context) {
ScreenHelper(mContext).setScreen(it)
}
You should use this. it is referred as shorthand if there is only one parameter in lambdas.
context?.let {
it.resources.getInt(R.int.anyint) // just for example
}
In above snippet, it is the shorthand for lamda parameter(in case of only one parameter).
context?.let { cxt -> // here we have manually defined a parameter
cxt.resources.getInt(R.int.anyint) // just for an example
}
In this snippet, instead of it we have created cxt that is exactly same as it.
Actually you are taking the concept of Extension function wrong.
You are creating a data class ScreenDef and want to create an extension function to it, why? If you really want to have a member function just create a normal class and have a function in it.
Extension function should be created when target class is not maintained by you. For example: Activity, Fragments are not maintained by you and if you want to add a custom function, you have to extend them and do it. So to prevent it extension function comes into picture and they are really handy that's why we love it.
You can rather argue, whats wrong with creating extension function for a class created by us. It may or might not be true. It actually depends.
Let's take an example, suppose we have developed a library to draw simple symbols on canvas and there are several function we have created. It turned out to be so good that people are using it, we decided to created advanced version, that can draw more complex symbols that requires using our already developed simple lib. So when we extend the classes of simple lib we might need some functionality to improve some thing etc. in that case if we have imported our simple lib as dependency then its good to create extension function otherwise we would have to create one more child of that class and create desired function. If we have import our lib as source code, we can just go to the source fine and create a function inside it.
I hope it helps.
I have created a custom view in android. one of the methods has a signature like this:
fun show(CategoryFilterModel model) {/*...*/}
and it works fine. and now i'd like to create a overloaded function which would look like this if i did it by adding it to the custom view class:
fun show(ShopFilterModel model) {/*...*/}
Notice the type is different so this is a method overload.
a thought came to me that i could instead use an extension in kotlin to add another method to the class.
so it would like something like this:
fun MyCustomView.show(ShopFilterModel: model){
}
is this advised or should i only add utility methods with extensions ? Are there any overheads ?
It’s not only for utilities, as you can read in this great answer, which lists pretty much all use cases.
Imho, if you have control over that class you want to extend with a method, there’s no problem to add the method directly to it as opposed to doing it with an extension method. Yet, technically you can consider doing this. Please be aware that calling such an extension function from Java isn’t very idiomatic because it will be compiled to a static function. If it’s ever going to be invoked from Java, I’d rather use ordinary methods when possible.
It´s a good idea to use kotlin extensions all over the code?
I miss a lot the extensions from iOS, but this is a good way to use those kind of things in android?
Refering to http://antonioleiva.com/kotlin-android-extension-functions/
Is there a better solution for this?
To expand a little bit more on Andrey Breslav's answer a bit, Kotlin extension functions do compile down to static java methods, so most general purpose extension functions carry no overhead. But there is one edge case you need to look out for that Jake Wharton calls out in the first few min of this talk at Google IO.
That is when you pass in higher order functions (lambdas), as a parameter to the extension function like so:
fun View.doSomething(block: () -> Unit) {
//do something
}
This code would take a performance hit because lambda's under the hood have to create an anonymous class under the hood which can eat up methods and cause class loading. This is a very simple fix by adding the inline keyword to the function which will essentially inline your code into all of this call sites functions so you will not take a performance hit each time the extension function is called.
inline fun View.doSomething(block: () -> Unit) {
//do something
}
Extension functions in Kotlin are compiled to normal Java methods. For example, when you define a function in your package it turns into a static method in a Java class. There's no overhead compared to simply calling a static utility