0

I know there was documented in main kotlin page, but there is no clear explanation about when to use it, why this function need a receiver as a function. What would be the correct way to create a correct definition of inline function.

  1. This is inline function
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY, block: (date: String) -> String): String {
    return try {
        var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
        val date = sdf.parse(this.orEmpty())
        sdf = SimpleDateFormat(outputDate, Locale.US)
        block(sdf.format(date ?: Date()).orEmpty())
    } catch (ex: Exception) {
        block("")
    }
}

  1. The same way we also can do
inline fun String?.toDateString(rawDateFormat: String = MMMM_DD_YYYY, outputDate: String = MM_DD_YYYY): String {
    return try {
        var sdf = SimpleDateFormat(rawDateFormat, Locale.US)
        val date = sdf.parse(this.orEmpty())
        sdf = SimpleDateFormat(outputDate, Locale.US)
        sdf.format(date ?: Date()).orEmpty()
    } catch (ex: Exception) {
        ""
    }
}

If anyone could have a detail explanation about this?

Edit:

I understand that the inline function will insert the code whenever it called by the compiler. But this come to my attention, when I want to use inline function without functional parameter receiver type the warning show as this in which should have a better explain. I also want to understand why this is such recommendation.

enter image description here

1 Answer 1

2

There are few things here.

First, you ask about using a function with a receiver.  In both cases here, the receiver is the String? part of String?.toDateString().  It means that you can call the function as if it were a method of String, e.g. "2021-01-15 12:00:00".toDateString(…).

The original String? is accessible as this within the function; you can see it in the sdf.parse(this.orEmpty()) call.  (It's not always as obvious as this; you could simply call sdf.parse(orEmpty()), where the this. is implied.)

Then you ask about inline functions.  All you have to do is to mark the function as inline, and the compiler will automatically insert its code wherever it's called, instead of defining a function in the usual way.  But you don't need to worry about how it's implemented; there are just a few visible effects in the code.  In particular, if a function is inline and accepts a function parameter, then its lambda can do a few things (such as calling return) that it couldn't otherwise do.

Which leads us to what I think is your real question: about the block function parameter.  Your first example has this parameter, with the type (date: String) -> String — i.e. a function taking a single String parameter and returning another String.  (The technical term for this is that toDateString() is a higher-order function.)

The toDateString() function calls this block function before returning, applying it to the date string it has formatted before returning it to the caller.

As to why it does this, it's hard to tell.  That's why we put documentation comments before functions: to explain anything that's not obvious from the code!  Ideally, there would be a comment explaining why you're required to supply a block lamdba (or function reference), when it's not vital to what the function does.

There are times when blocks passed this way are very useful.  For example, the joinToString() function accepts an optional transform parameter, which it applies to each item before joining it to the list.  If it didn't, the effect would be a lot more awkward to obtain.  (You'd probably have to apply a map() to the collection before calling joinToString(), which would be less efficient.)

But this isn't one of those times.  As your second example shows, toDateString() would work perfectly well without the block parameter — and then if you needed to pass the result through another function, you could just call it on toDateString()'s result.

Perhaps if you included a link to the ‘main kotlin page’ where you saw this, it might give some more context?


The edited question also asks about the IDE warning.  This is shown when it thinks inlining a function won't give a significant improvement.

When no lambdas are involved, the only potential benefit from inlining a function is performance, and that's a trade-off.  It might avoid the overhead of a function call wherever it's called — but the Java runtime will often inline small functions anyway, all on its own.  And having the compiler do the inlining comes at the cost of duplicating the function's code everywhere it's called; the increased code size is less likely to fit into memory caches, and less likely to be optimised by the Java runtime — so that can end up reducing the performance overall.  Because this isn't always obvious, the IDE gives a warning.

It's different when lambdas are involved, though.  In that case, inlining affects functionality: for example, it allows non-local returns and reified type parameters.  So in that case there are good reasons for using inline regardless of any performance implications, and the IDE doesn't give the warning.

(In fact, if a function calls a lambda it's passed, inlining can have a more significant performance benefit: not only does the function itself get inlined, but the lambda itself usually does as well, removing two levels of function call — and the lambda is often called repeatedly, so there can be a real saving.)

Sign up to request clarification or add additional context in comments.

1 Comment

Thank for the great explanation, I have add more details about the questions that put on the attention.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.