Is reflection being used when using the 'is' operator in Kotlin - android

As MVI is getting more and more popular in Android development, the use of Sealed classes increases as well. And we know that we have to determine the actual type of the Sealed class in order to continue with a particular flow from our logic.
So does Kotlin use reflection when using the 'is' operator for type checks? Tried to go through the documentation, but couldn't find anything about that. https://kotlinlang.org/docs/typecasts.html

Depends on the definition of reflection you’re using. Often “reflection” in the JVM world is used to describe specifically the String-based code meta data inspection from the java.lang.reflect package (or Kotlin reflection dependency) that is considered to be inefficient. But a more general definition of “reflection” is any code introspection. is arguably fits the second definition, but it is fast/optimized and not part of the first definition.

The 'is' operator in Kotlin is used for type checks, for example to check if an object is an instance of a particular class or its subclasses. The 'is' operator does not use reflection to perform type checks. Instead, the type check is done at compile-time, and the generated bytecode contains an instanceof check, which is a standard JVM instruction for performing type checks.
In the case of sealed classes, the use of 'is' operator will not use reflection as well, it's a compile-time check, that's why when using the 'is' operator with a sealed class, the compiler is able to perform type checks and generate the appropriate bytecode at compile-time.
Using the 'is' operator is much more efficient than using reflection, as it is a compile-time check and it does not require any runtime overhead, while reflection can be relatively slow, as it requires the JVM to perform additional lookups and checks at runtime.
So, in summary, the 'is' operator in Kotlin does not use reflection for type checks. It's a compile-time check, which is much more efficient than using reflection.

Related

How to check stability of a class inferred by Compose compiler?

There are #Immutable and #Stable annotations available for developers to mark their classes with. But I'm not quite sure when you need to annotate your classes and when it is inferred automatically. E.g. deeply-immutable data classes seems to be recognized as immutable by default. But you cannot be quite sure unless you log all #Composable calls and see how it behaves. And not knowing what is actually going on is somewhat infuriating for me as a programmer.
I wonder if there are more reasonable ways to see what immutability/stability Compose compiler infers for custom classes?
And if there are no clever ways to check it, what would be the rule of thumb for using #Immutable and #Stable annotations?
You can enable the compose compiler metrics to see what the compiler considers is stable. https://github.com/androidx/androidx/blob/androidx-main/compose/compiler/design/compiler-metrics.md

What is the Performance impact of Sealed Classes in the context of Android?

In Android, it is advisable to refrain from using enum due to performance issue. This is true until recently, where it was announced in Google IO 2018 that enums are now safe to use though avoiding them is still advisable for a more performant app.
My question is:
Can we use kotlin sealed classes extensively in android?
It seems like sealed classes are extensions of enums. If so, should we use sealed classes similar to enums?
Thanks in advance.
The advice to stay away from enum on Android is exaggerated. Avoiding enums makes sense for the Android APIs: they heavily use special constants, there are very many of those objects live in an application, and they are performance-critical.
Your custom application code would probably want to use just a few enums to express entities from business logic. Creating a dozen, or even a few hundred, enum instances will leave an imperceptible footprint.
The same advice extends to sealed classes: by all means use them and improve the quality of your code. Stop to think about your choice only if you plan to embark on building a 100 KLOC application with thousands upon thousands of enum-like constants and classes.
Enums
Garbage Collection
Under the hood, enums are static members of the class, so they don't get garbage collected. They stay in memory for the lifespan of your app. This can be an upside or a downside.
The garbage collection process is expensive in terms of CPU usage. The same is true for object creation, you don't want to create the same objects again and again. So, with enums, you save the cost of garbage collection as well as object creation. This is the upside.
The downside is that the enums stay in memory even when they are not in use, this can keep the memory occupied all the time.
Factors to Consider
You don't need to worry about all this, if you have 100 to 200 enums in your app. But when you have more than that, you have a decision to make whether you should go for enums depending on the facts such as the number of enums, whether they will be in use all the time and the amount of memory allocated to your JVM.
Comparison
The comparison of enum values is faster in the when expression because under the hood it uses tableswitch to compare the objects.
Android
In Android, when the optimization is enabled, the Proguard converts the enums that don't have functions and properties to integers. This way, you get the type-safety of the enums at compile-time and the performance of the ints at runtime!
Sealed Classes
Garbage Collection
Sealed classes are just regular classes with the only exception that they need to be extended in the same package and the same compilation unit. So, their performance is equivalent to regular classes.
Objects of the subtypes of the sealed classes get garbage collected like the objects of regular classes. So, you have to bear the cost of garbage collection as well as object creation.
Factors to Consider
When you have the low memory constraints, you may consider using sealed classes instead of enums, if you need thousands of objects. Because the garbage collector can collect the objects when the memory is low and the objects are not in use.
If you use object declaration for extending the sealed class, the objects act as singletons and they won't be garbage collected, this behaviour is similar to enums. But there is an additional cost of loading the associated classes and keeping them in memory because object declarations have associated classes with the same names as the objects under the hood.
Comparison
The comparison of sealed class' types is slower in the when expression because under the hood it uses instanceof to compare the types. The speed difference between enums and sealed classes, in this case, is very little though. It matters only when you are comparing thousands of constants in a loop.
Android
Proguard doesn't have any integer optimization like enums for sealed classes. So, if you want to have just constants without functions and properties in Android, sticking to enums is a better idea.
That's it! Hope that helps.
The performance impact of sealed classes is the same as for any other classes. If you create an instance of a class extending a sealed class, it will be a new instance, so it will need to be garbage-collected. If you have an object extending a sealed class, it will be a singleton and will not need to be collected (just like an enum constant)..

How #OnLifecycleEvent annotated methods from Architecture Components get hooked up with the LifecycleOwner?

It looks like we don't need to use kapt for #OnLifecycleEvent annotations to work. So, how do they get hooked up? Is it some kind of runtime annotation processing?
I'm asking because I'm curious what are the costs of using these annotations. Is using them affects application startup time? Or project compile time?
They are using reflection to find annotated functions with #OnLifecycleEvent. This is the real need why classes should implement LifecycleObserver. If there was kapt to do, that probably there shouldn't have been any interface to implement.
The resolution is on runtime, since the retention is set to RetentionPolicy.RUNTIME.
Reflection is expensive and therefore they are building static cache of each methods and uses the method reference, yes still reflection, to invoke each of them. I have no figures to provide how directly it affects the start up time.

Do lambdas in Android N jack compiler hold references to enclosing class?

Unlike anonymous inner classes, Java 8 lambdas don't hold references to the enclosing (parent) class. Android N adds support for lambdas.
However, they are implemented in the Jack compiler using anonymous inner classes for backward compatibility, as the note in the link states.
Does this mean that lambdas in Android classes compiled using Jack (and not retrolambda) will hold references to the enclosing class?
I know that one reason many people were excited about lambdas is to avoid Fragment or Activity leaks when using them, but at a cursory glance, it looks like using jack compiler will not give that benefit.
I think the phrase "anonymous class" shouldn't be interpreted too literally here. In my understanding, the only thing they want to tell us is that Jack generates the classes at compile time (as opposed to the runtime approach of Java 8).
From the JackIrBuilder code I'd guess that the generated IR looks very similar to the bytecode that would be generated by retrolambda.
Jack seems to create a synthetic method containing the lambda body in the enclosing type and passes the reference of the enclosing instance to the generated class' constructor only in those cases where it is needed, i.e. when members of the enclosing instance are captured.
Reference: https://android.googlesource.com/toolchain/jack/+/0af676c4779c5b55fb321f491811516f3d74ed93/jack/src/com/android/jack/ir/impl/JackIrBuilder.java
So, from what I understand, the answer is: only when something needs to be captured from the enclosing instance.

How can I define a custom android annotation (Eg. #Background)

Can any one suggest a proper order to define a custom annotation in JAVA(Android). So that if I annotate a method with #Background annotation, the method should work on background thread.
This might be of use for your need case Creating custom Annotations. It seems like you would need to do #Retention(RetentionPolicy.RUNTIME) and #Target(ElementType.METHOD) scope to achieve what you want. Then as you can see in the first example, you would go into the object and etc.
For a good example, look at what they do in Dagger
As a final note, this is old and you've probably designed what you wanted, but it probably isn't a good idea to do what you asked. There is cost to annotation usage and Runnable was built basically for what you seem to be trying to do.
Android's Annotation subtypes provide a wide variety of tools for what you are trying to do. In particular, take a look at the thread annotations; I suspect that the #WorkerThread annotation does just what you want. The code inspection tools in Android Studio recognize these annotations and will automatically flag any code that it recognizes as violating the threading requirements (e.g., calling a UI thread method from a method annotated as #WorkerThread).
The code inspection tools also allow you to define your own annotations, but these are somewhat limited in what they can do. This is discussed in the section Creating Enumerated Annotations.
You can't use a custom annotation in JAVA(Android), because the android compiler doesn't support it. But maybe the follwing site can be helpful for you: http://androidannotations.org/

Categories

Resources