Why do we use inline keyword on a variable in kotlin? - android

What I can understand from google documentation is that we can use inline keyword to enhance the performance and reduce the memory allocation on runtime in case of high order function but why in this case we are inlining a variable
#PublishedApi
internal inline val <T : Any> T.loggingTag: String
get() {
val tag = this::class.java.name.substringAfterLast(".")
if (tag.contains("$")) {
return tag.substringBefore("$")
}
return tag
}
in case you are curious the logging tag variable is used in an inline function
inline fun <reified T : Any> T.errorLog(error: Throwable? = null, message: String? = null) {
errorLog(loggingTag, error, message)
}
also the errorLog function inlined even it doesn't take an other function as a parameters does anyone able to explain for me this ?
inline fun errorLog(tag: String, error: Throwable? = null, message: String? = null) {
Timber.tag(tag).e(error, message)
}

That val isn't a variable. It's a property. If you see val or var outside of a function, it's a property, not a variable.
Properties have getter functions. In your example, the getter function is what is being marked as inline.
There are two main reasons to use inline functions:
In a higher order function, it avoids allocating a function object to represent the function parameter (lambda or function reference) being passed to it. It also allows lambdas that are passed to use keywords that are normally restricted to local use, such as return, break, and continue.
It is necessary for reified generics. If a function needs to be able to inspect one of its generic types, the type needs to be marked as reified, which in turn requires the function to be marked inline.
Generally, you want to avoid using inline if a function doesn't fit one of the above cases, because actual function calls themselves are rather trivial, and if you inline a function that is used frequently (the only kind of function you would want to be optimized), then its code is going to be repeated everywhere it's used in your compiled app, increasing the size of the app.
An exception might be if the inline function contains only one function call, so it's not really increasing code size.
I do not see any reason the inline keyword is needed for the extension property in your first block of code. It is not a higher-order function, and it is a multi-line function. I also don't see why it is defined as a generic function, since the type T is not used for anything inside the function. I think I would define it as:
internal val Any.loggingTag: String
Also, in your second block of code, I don't see any reason why there is a generic type, since it is not used in that function. It could be defined as:
fun Any.errorLog(error: Throwable? = null, message: String? = null) {
The third block of code doesn't benefit much from inlining either. It's not a higher-order function. If function call overhead is that much of an issue for performance, it would make more sense to fork Timber and rewrite how it creates tags, because using custom temporary tags like that in Timber involves a few method calls under the hood.

The inline keyword is used to make functions inline, meaning that when a function is called, its body is copied and pasted into the caller's code instead of making a function call. This allows for reduced execution time, as there is no need to jump to another function and back. Inline functions can also be used to reduce code size and improve readability.

Related

Set property type from specific class as parameter type

I have this sample data class:
data class Car ( var id: String )
Now I can create a fun as this:
fun doWhatever(id: String){}
My problem is that if my customer then tells me that Id is an int, I have to change it in both places.
So what I want is to set Car.id type as refence in fun doWhatever, something like this:
fun doWhatever(id: propertyTypeOfCarId){}
So I if the customer changes type, I only have to change it in the class.
I read all kind of posts, but I wasnt able to find the answer. Any idea how to achieve it?
If this isn't something you expect to be doing regularly, consider just using the refactoring tools the IDE provides. You code to handle a specific set of data, and if the structure of that data changes, you have to adapt the code to fit it. Baking in a bunch of "what if" functionality can add complexity, compared to just saying a String is a String and changing it if it ever needs changing, using the tools provided to make that as quick and easy as possible.
But sometimes you need to do this kind of thing, and Kotlin has some nice language features it can be worth using, like type aliases:
typealias CarId = String
data class Car(var id: CarId)
fun doWhatever(id: CarId){}
Two benefits here: the actual type is only defined in one place, so you can change that String to an Int without needing to change anything else - except stuff that relied on the ID being a String specifically of course
The other benefit is you're actually adding some semantic information by using that very specific type. That function isn't supposed to just take any old String - it's specifically meant to handle CarIds. It tells you what it's for, and that can make your code a lot easier to understand
(The function will accept Strings, because CarId is just an alias - an alternative name for a String - so it's not a way to enforce structure on your code, just a way to make it nicer to read and write. You can't define a new type that is a String in Kotlin unfortunately)
If the number of id types you support is limited, you can simply use method overloading:
fun doWhatever(id: String){}
fun doWhatever(id: Int){}
// etc.
Alternatively, you can use a reified generic parameter in your method to support any number of types:
inline fun <reified T> doWhatever(id: T) {
when (T::class) {
Int::class -> {}
String::class -> {}
}
}

How to make a function that returns a generic object?

I am trying to make a function that returns a T/Any object. The only thing is that i am not quite sure how to do it.
fun readMockData(context: Context, filename: String): Any {
val json = context.assets.open("$filename.json").bufferedReader().use(BufferedReader::readText)
return RetrofitSingleton.GSON.fromJson(json, object : TypeToken<Any>() {}.type)
}
This is what i tried at first, but i am getting an error.
How am i supposed to make this function properly?
If I understand your problem correctly, this is what you need:
#OptIn(ExperimentalStdlibApi::class)
inline fun <reified T> readMockData(context: Context, filename: String): T {
val json = context.assets.open("$filename.json").bufferedReader().use(BufferedReader::readText)
return RetrofitSingleton.GSON.fromJson(json, typeOf<T>().javaType)
}
Note it has to be inline, because otherwise there is no way to acquire a type. If your function is longer than above, it may be a good idea to split it into an inline reified wrapper and the main function that accepts Type as a parameter.
It uses reflection, so you need to add a dependency to it. Also, typeOf() is experimental, but from my experience it just works (at least on JVM) and it is there for a long time, so I guess it won't change.

What is the meaning of "ClassInstance.[Someclass::class.java]" in Kotlin?

I've seen people using ViewModelProvider[Someclass::class.java] instead of ViewModelProvider.get(Someclass::class.java), and it compiles in Android Studio. The problem is that I couldn't find any documentation of such usage online.
With kotlin you can add operator modifiers to your function. So if you have some class with a get function and you might want to access it with [], like an array or map, you could add operator modifier.
Square brackets are translated to calls to get and set with appropriate numbers of arguments.
So this only works for functions with name get or set!
class Provider {
operator fun get(key: String)
operator fun set(key: String, value: String) { ... }
}
Then you can call the function like:
Provider().get("key") // IDE hint: should be replaced with indexing operator
Provider()["key"] // calls get()
Provider().set("key", "value") // IDE hint: should be replaced with indexing operator
Provider()["key"] = "value" // calls set()
Reference
See Kotlin Operator overloading
Kotlin allows operator overloading by marking a function as an operator function. The square brackets notation is one of these operators (indexed access operator).
Kotlin automatically interprets Java functions as operator functions if their name and signature match the requirements of a Kotlin operator function. In this case, it interprets functions named get as an "indexed access operator" if they return something, which allows you to use square bracket notation.
ViewModelProvider[Someclass::class.java] is a shorter version of ViewModelProvider.get(Someclass::class.java) there is no differences.

Return type is 'Unit?', which is not a subtype of overridden

Today while programming I found some odd behaviour in Kotlin. I could easily go around it, but I wonder if there is some reason to it or if it is a bug in Kotlin.
I have the following interface of a delegate which delegates the showing of a dialog to the Activity.
interface ViewModelDelegate {
fun showWarningDialog(textResource: Int)
}
I want to implement it as following in the Activity. Since I know I can only do it with a context and the Activity.getContext() may return null, I wrap the code in context?.let
override fun showWarningDialog(textResource: Int) = context?.let {
//show dialog
}
However this gives me a compile error:
Return type of 'showWarningDialog' is not a subtype of the return type of the overridden member 'public abstract fun showWarningDialog(textResource: Int): Unit defined in com.some.class.path'
Which really confused me, because I don't want to return anything. So since let returns whatever the function inside returns, I was wondering if I could fix it by writing a version of let which does not return anything.
fun <T, R> T.myLet(block: (T) -> R) {
let(block)
}
However this did not remove the compiler error. I found then that the mouseover text over the error gives more information (would be nice if the compiler did). It says:
Return type is 'Unit?', which is not a subtype of overridden
Now that tells me more about the problem. Because the function context?let call may not happen, it could return null. Now there are multiple ways to go around this. I could add ?: Unit too the end of the function call or I could define showWarningDialog to return Unit? which will allow me to call it just fine in most cases. However none of these solutions are desireable. I will probably just make a normal method and call the let inside of that instead of delegating the call to it. Costs me another level of indentation and an extra vertical line:
override fun showWarningDialog(textResource: Int) {
context?.let {
//show dialog
}
}
My question is, is this behaviour intended? Why or when would this be useful that a function that returns Unit cannot be delegated to an optional function call. I am very confused by this behaviour.
Single expression function
fun foo() = <expression>
by language design is equivalent to
fun foo(): <ReturnType> {
return <expression>
}
And because Unit? is not a not a subtype of Unit, you can't return it in from a function, which returns Unit. In this sense Unit just another type in the type system, it's not something magical. So it works just as it's supposed to work with any other type.
Why or when would this be useful that a function that returns Unit cannot be delegated to an optional function call.
So basically the question is why language designers did not created a special handling to accept Unit? from a function declaring Unit as a return type. I can think about a few reasons:
It requires to create this special handling in the compiler. Special cases lead to bugs, break slim language design and complicate documentation.
As it had to be a special case, it would be not really clear and predictable for programmers. Currently it works in the same way for all types, no special treatments. It makes the language predictable, you don't need to check the documentation for every type to see if it's treated specially.
It also adds some additional safety, so to make you notice that your expression can actually skip the calculation.
So trying to summarize, I would say making this case work does not add much of value but can potentially bring some issues. That's probably why they did not add it to the language.
lets discuss this case when you have return type for example String
interface someInterface{
fun somFun():String
}
class someClass : someInterface {
var someString:String? = null
override fun somFun()=someString?.let {
//not working
it
}
override fun somFun()=someString?.let {
//working
it
}?:""
}
so what we see that when parents return type is String you cannot return Strin? it is jus kotlins nullSafety ,
what is different when you don't have return type ? lets change the code above a little
interface someInterface{
fun somFun():String
fun unitFun()
}
class someClass : someInterface {
var someString:String? = null
override fun unitFun() {
//if it is possible to return null in here
}
override fun somFun()=someString?.let {
val someresult = unitFun().toString() //you will get crash
it
}?:""
}
now we have another function without return type (unitFun Unit)
so if you can return Unit? in your subclass it will cause a crash when you want to use the result of method because it is defined asUnit and you dont need any null checks.
generally it means Unit is also type and you need to keep it null safe .

Lifecycle methods in statically typed languages

In the last year I've become a mobile developer and a functional programming admirer.
In each of the mobile arenas there are components with lifecycle methods that make up the meat of the app. The following will use Android and Kotlin as examples, but the same applies to iOS and Swift.
In Android, there are Activity's with lifecycle methods like onCreate(). You might also define a function, onButtonClicked(), which will do exactly what the name describes.
For the purposes of the question, let's say there's a variable defined in onCreate() that is used in a button click handler onButtonClickedPrintMessageLength() (This is usually the case - onCreate() is essentially Activity's setup method).
The example class would look like this:
class ExampleActivity: Activity() {
var savedStateMessage: String? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
savedStateMessage = "Hello World!"
}
fun onButtonClickedPrintMessageLength() {
System.out.println(savedStateMessage?.length)
}
}
Notice the declaration of savedStateMessage as a String? (nullable string) and the use of ?. (null safe call). These are required because the compiler cant guarantee that onCreate() will be called before onButtonClickedPrintMessageLength(). As developers though, we know that onCreate will always be called first* **.
My question is how can I tell the compiler about the guaranteed order of these methods and eliminate the null checking behavior?
* I suppose it's possible to new up our ExampleActivity and call onButtonClickedPrintMessageLength() directly, thus sidestepping the Android framework and lifecycle methods, but the compiler/JVM would likely run into an error before anything interesting happened.
** The guarantee that onCreate is called first is provided by the Android framework, which is an external source of truth and might break/function differently in the future. Seeing that all Android apps are based on this source of truth though, I believe it's safe to trust.
Although this won't answer your actual question, in Kotlin you can use lateinit to tell the compiler that you'll initialize a var at a later point in time:
lateinit var savedStateMessage: String
You'll get a very specific UninitializedPropertyAccessException if you try to use this variable before initializing it. This feature is useful in use cases like JUnit, where you'd usually initialize variables in #Before-annotated method, and Android Activitys, where you don't have access to the constructor and initialize stuff in onCreate().
As mentioned in another answer, lateinit is available as an option to defer initialization to a later point in a guaranteed lifecycle. An alternative is to use a delegate:
var savedStateMessage: String by Delegates.notNull()
Which is equivalent, in that it will report an error if you access the variable before initializing it.
In Swift this is where you would use an implicitly-unwrapped Optional:
class Example: CustomStringConvertible {
var savedStateMessage: String! // implicitly-unwrapped Optional<String>
var description: String { return savedStateMessage }
init() {
savedStateMessage = "Hello World!"
}
}
print(Example()) // => "Hello World!\n"
By using the operator ! at the end of String in the second line of the example you are promising that the variable will be set before it can be used. This is accomplished in the init method of the example. It's still an Optional but code can treat it as a String since it will be automatically unwrapped before each use. You must take care that the variable is never set to nil when it might be accessed or a runtime exception may be generated.

Categories

Resources