Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Use inline keyword for small, private functions in kotlin?

I would like to know, if it is a good idea to inline small, private functions? These functions, in my case, are only there for readability purposes and I know, that they are only called a few times, so the bigger bytecode size is insignificant.
I know, that the performance boost may also be insignificant, because I am not passing functional types (and the compiler actually warns me about that), but lets assume that it is a hot spot in our application.

Actual example:

I hava a theoretically infinite tape of symbols (like the one of a turing machine) which is modeled by tow arrays (left and right for positions < 0 and positions >= 0, respectively). Now I have read and write operations which are assumed to be called a lot.

In java I had:

/**
 * @param cell the cell
 * @return the symbol at the specified cell
 */
public char read(int cell) {
    char[] tape;
    if (cell < 0) {
        tape = left;
        cell = -cell - 1;
    } else {
        tape = right;
    }
    return cell < tape.length ? tape[cell] : blank;
}

/**
 * Writes a symbol to the specified cell.
 * @param c    the symbol
 * @param cell the cell
 */
public void write(char c, int cell) {
    char[] tape;
    if (cell < 0) {
        cell = -cell - 1;
        if (cell >= left.length) left = expandArray(left, cell, blank);
        tape = left;
    } else {
        if (cell >= right.length) right = expandArray(right, cell, blank);
        tape = right;
    }
    tape[cell] = c;
}

Now I wanted to translate the snippet to kotlin, read about inline functions and come up with this:

fun read(cell: Int = headPosition) = when {
    cell < 0 -> read(left, -cell - 1)
    else     -> read(right, cell)
}

private inline fun read(tape: CharArray, cell: Int): Char {
    return if (cell < tape.size) tape[cell] else blank
}

fun write(c: Char, cell: Int = headPosition) = when {
    cell < 0 -> left = write(c, left, -cell - 1)
    else -> right = write(c, right, cell)
}

private inline fun write(c: Char, tape: CharArray, cell: Int): CharArray = when {
    cell >= tape.size -> expandArray(tape, cell, blank)
    else -> tape
}.also { it[cell] = c }

I personally think, especially the read functions, are easy to read.
So is this a good idea and can I ignore the warning of the IDE? Or am I missing something? Maybe there is a best practice or other pattern to write these functions without repeading (almost) the same lines twice (for position < 0 and position >= 0).

like image 259
aagapow Avatar asked May 26 '19 11:05

aagapow


People also ask

What is inline function in Kotlin Mindorks?

Inline function instruct compiler to insert complete body of the function wherever that function got used in the code. Advantages of inline function are as follows: Function call overhead doesn't occur. It also saves the overhead of push/pop variables on the stack when the function is called.

What is the function of the __ inline?

The __inline keyword causes a function to be inlined only if you specify the optimize option. If optimize is specified, whether or not __inline is honored depends on the setting of the inline optimizer option. By default, the inline option is in effect whenever the optimizer is run.

How do you use inline keywords?

Inline function and classes: If you need to explicitly declare inline function in the class then just declare the function inside the class and define it outside the class using inline keyword. };


1 Answers

There is no need to inline a very small repeatedly used function since the JVM JIT will likely do this for you anyway when it deems it to be appropriate. If you inline the function you do cause a bit of bloat in the generated bytecode but otherwise, there isn't a lot of harm there either for functions that are not called from many different points in your code. Bytecode bloat is worse for larger inline functions, functions used from many places in your code, and inline functions that call other inline functions. Your case does not cause much at all.

Short methods benefit heavily from inlining and as you can read in When Short Methods Pay Off: JIT Inlining:

A method is eligible for inlining if:

  • It’s small – the bytecode size is smaller than 35 bytes (can be overridden by the -XX:MaxInlineSize=X flag).
  • It’s called frequently (it’s hot) and it’s smaller than 325 bytes (can be overridden by the -XX:MaxFreqInlineSize=X flag).

If you exceed these parameters or want to pre-warm up the inlining you can use the inline keyword to cause it to happen at compilation time.

You also would want to use inline on small functions when:

  • You want to allow a lambda passed to the function to do a non-local return
  • You want to use reified generic type parameters.
  • You are writing a function that accepts a lambda that it uses in high repetition and you want to avoid the function call overhead to the lambda. By inlining this type of function, the Kotlin compiler also inlines the lambda.
like image 163
2 revs Avatar answered Dec 14 '22 21:12

2 revs