Kotlin fails to inline some bodies - kotlin

I have an inline function which accepts two lambdas. This function is called in a hotspot of my code and, despite it being inline, thousands of objects are created for the bodies.
What's interesting is commenting out, or replacing the bodies with simple calls like printlns and everything works perfectly. But for some reason with my specific use, it seems like inline is failing to do its job!
How can I resolve this? And what are the limitations associated with inlining bodies? Is this a bug?
My use case:
fun PlayerSend.sync() = reusable({
val packet = this
it.syncMovement(packet)
reusable({ if (it.updateRequired) it.sync(this) }, {
packet.bits(8, 0 /* amount of players to update */)
if (readable > 0) {
packet.bits(11, 2047).byteAccess() + this
} else packet.byteAccess()
})
}, { ses + 81.byte + readable.short + this })
The method header:
inline fun <R1, R2> reusable(use: ByteBufPacketeer.() -> R1, after: ByteBufPacketeer.() -> R2) {
val reusables = Reusables.get()
val count = ReuseablesCount.get()
ReuseablesCount.set(if (count + 1 >= reusables.size) 0 else count + 1)
with(reusables[count]) {
use()
after()
clear()
}
}

Related

How can I yield in a recursively generated sequence

I have a function generating values. It does so by recursively calling itself, and whenever the base case is reached, a value is emitted. This is just a toy example, the real one is much more complicated, and thus harder to transform to something non-recursive.
I would like to do this as a sequence. But doing this won't compile on the line I yield, with the message
Suspension functions can be called only within coroutine body
Here's the attempt:
fun test1() = sequence {
fun a(i: Int) {
if (i > 4) {
yield(i) // <- fails to compile
} else {
a(i + 1)
a(i + 2)
a(i + 3)
}
}
a(1)
}
If I try to add the suspend keyword to function a, I instead get the error
Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope
I can make it work, by instead returning all the values and doing a yieldAll. The problem with this, however, is that it needs to do the whole computation and hold all the results in memory before the sequence can be used. For my case, this won't work as I'd run out of memory, or may even have an almost infinite amount of results where I only want to take a few.
So this works, but is not optimal
fun test2() = sequence {
fun a(i: Int): List<Int> {
if (i > 4) {
return listOf(i)
} else {
return listOf(
a(i + 1),
a(i + 2),
a(i + 3)
).flatten()
}
}
yieldAll(a(1))
}
Any ideas on how to combine sequences with a recursive function, allowing me to yield values without pre-computing and allocating memory for all of them?
How about making a return a lazy Sequence?
fun a(i: Int): Sequence<Int> =
sequence {
if (i > 4) {
// println("yielding $i")
yield(i)
} else {
yieldAll(a(i + 1)) // this yieldAll is lazy
yieldAll(a(i + 2))
yieldAll(a(i + 3))
}
}
fun test1() = a(1)
If you uncomment the println, and loop over the sequence, you will see that it is indeed lazy:
for (i in test1()) {
println("printing $i")
}
Output:
yielding 5
printing 5
yielding 6
printing 6
yielding 7
printing 7
yielding 5
printing 5
yielding 6
printing 6
yielding 5
printing 5
yielding 6
printing 6
yielding 7
printing 7
...
You can make the inner function a suspend function that is an extension of SequenceScope. The Sequence builder uses a special kind of coroutine that's limited to only calling suspend function extensions of SequenceScope. Presumably this is because Sequences are intended to be used only as synchronous, non-suspending iterables. Since yield() is one of these SequenceScope suspend functions, you have to make your function also a suspend extension function.
fun test1() = sequence {
suspend fun SequenceScope<Int>.a(i: Int) {
if (i > 4) {
yield(i)
} else {
a(i + 1)
a(i + 2)
a(i + 3)
}
}
a(1)
}

When is it a block and when is it a lambda?

How does the Kotlin compiler decide whether an expression enclosed in { } is a block or a lambda?
Consider this:
val a: Int
if (cond)
a = 1
else
a = 2
can be written more succinctly as:
val a =
if (cond)
1
else
2
Similarly, one might think that this:
val a: () -> Int
if (cond)
a = { 1 }
else
a = { 2 }
should be able to be written more succinctly like this:
val a =
if (cond)
{ 1 }
else
{ 2 }
But this is not the same: a is now an Int, and not of type () -> Int, because now the { 1 } is no longer a lambda. What are the rules that say whether something is a lambda or a block?
I didn't look into the Kotlin lexer, but I guess there are few possible places in the code where the compiler expects either a single expression or a block of code. That includes the code immediately following most of control flow statements like: if, else, while, when (one of its cases), etc. If you put { in one of these places, it will be interpreted as a start of the block of code related to this control flow statement and not as a lambda.
This is as simple as that. Note that even if you hint the compiler about the type, it still won't work:
// compile error
val a: () -> Int = if (cond)
{ 1 }
else
{ 2 }
It will be interpreted more like this:
// compile error
val a: () -> Int = if (cond) {
1
} else {
2
}
{ after if condition is always interpreted as a start of block of code. You need to put double {, } in cases like this:
// works fine
val a: () -> Int = if (cond) {
{ 1 }
} else {
{ 2 }
}
To put it very succinctly and easy to remember, the first opening brace after an if/when/else/for is always assumed to be the opening of a block. Use double braces if you want a lambda in there.
This is specified in the Kotlin Language Specification, section 1.2: Syntax Grammar:
The grammar defines a block as statements between { and }. In most cases (such as function bodies) the syntax is different between a block and a lambda. Where it is the same is in the usage of controlStructureBody - these are the places where the block has a value, or where you could put a non-block expression in its place. If you search the whole spec document for "controlStructureBody", you'll find it's used in the following places:
For statement
While statement
Do-while statement
If expression
When expression
When entry
In every other place where a value is required, a '{' signifies the start of a lambda.

Check if value is not equal in when()-statement

Is it possible to test a String for not being equal in a when-statement?
This is of course perfectly possible with a simpel if statement:
val storedValue = sharedPreferences.getString(identifier, NOT_SET)
if (storedValue != NOT_SET) {
super.setValue(storedValue)
}
However, I like how storedValue is scoped inside of the when-statement in this snippet:
when (val storedValue = sharedPreferences.getString(identifier, NOT_SET)) {
NOT_SET -> {}
else -> super.setValue(storedValue)
}
The downfall is the empty code block for the NOT_SET entry.
Is it possible to combine these two?
I'd like to scope storedValue and get rid of empty code blocks. The result would be comparable to:
when (val storedValue = sharedPreferences.getString(identifier, NOT_SET)) {
!NOT_SET -> super.setValue(storedValue)
}
Since SharedPreferences is part of the Android framework, this would another solution:
if (sharedPreferences.contains(identifier)) {
super.setValue(sharedPreferences.getString(identifier, null))
}
However, the goal of my question is deeper understanding of the possibilities of Kotlin, for the sake of learning.
As mentioned in the comments, negation is not directly supported like this in when statements (yet) even in Kotlin.
The most idiomatic way at the moment most probably is like:
val storedValue = sharedPreferences.getString(identifier, NOT_SET)
when {
storedValue != "NOT_SET" -> super.setValue(storedValue)
}
Another working variant utilizing !in in when could be for example:
when (val storedValue = sharedPreferences.getString(identifier, NOT_SET)) {
!in setOf("NOT_SET") -> super.setValue(storedValue)
}
And as both != and!in will compare case sensitively, so would make sense to get the string like sharedPreferences.getString(identifier, NOT_SET).toUpperCase(), or use equalsIgnoreCase in the first variant.

Traveling salesman with random initial solution, optimization algorithm returning unexpected result

I know traveling salesman is well known, but I need some help on why my optimization algorithm is returning an unexpected result. I have created an initial solution by selecting cities in a random order. I have also created a class with a constructor with the distance matrix and initial solution as parameters. The optimization algorithm is very simple; it swaps two cities and checks if the route distance has been improved, and if it has improved the best solution should be updated. This goes on for 6 iterations. The problem is that the it seems like the best solution is updated and overwritten even if the condition for overwriting it is not met. I will add an image showing the results from a test run.
It seems like the variable bestSolution is overwritten but not bestDistance. I must have some sort of tunnel vision, because I can't figure this one out even if the code is really simple. Can someone please chime in why bestSolution is overwritten and returned with unexpected result?
Code example below:
package RandomMethod
import GreedyHeuristic
import java.util.*
fun main(args: Array<String>) {
/*A B C*/
val distances = arrayOf(/*A*/ intArrayOf(0, 2, 7),
/*B*/ intArrayOf(2, 0, 9),
/*C*/ intArrayOf(7, 9, 0))
val initalSolution = findRandomRoute(distances)
println("Initial solution: $initalSolution")
println("Total distance: ${findTotalDistance(distances, initalSolution)}\n")
val optimizedSolution = GreedyHeuristic(distances, initalSolution).optimize()
println("\nOptimized solution with Greedy Heuristic: $optimizedSolution")
println("Total distance: ${findTotalDistance(distances, optimizedSolution)}")
}
fun areAllCitiesVisited(isCityVisited: Array<Boolean>): Boolean {
for (visited in isCityVisited) {
if (!visited) return false
}
return true
}
fun findTotalDistance(distances: Array<IntArray>, orderToBeVisited: MutableList<Int>): Int {
var totalDistance = 0
for (i in 0..orderToBeVisited.size - 2) {
val fromCityIndex = orderToBeVisited.get(i)
val toCityIndex = orderToBeVisited.get(i + 1)
totalDistance += distances[fromCityIndex].get(toCityIndex)
}
return totalDistance
}
fun findRandomRoute(distances: Array<IntArray>): MutableList<Int> {
val visitedCities: Array<Boolean> = Array(distances.size, {i -> false})
// Find starting city index. 0 = A, 1 = B, 2 = C .... N = X
var currentCity = Random().nextInt(distances.size)
val orderToBeVisited: MutableList<Int> = mutableListOf(currentCity)
visitedCities[currentCity] = true
while (!areAllCitiesVisited(visitedCities)) {
currentCity = Random().nextInt(distances.size)
if (!visitedCities[currentCity]) {
orderToBeVisited.add(currentCity)
visitedCities[currentCity] = true
}
}
return orderToBeVisited
}
And the class for optimization:
import java.util.*
class GreedyHeuristic(distances: Array<IntArray>, initialSoltion: MutableList<Int>) {
val mInitialSolution: MutableList<Int> = initialSoltion
val mDistances: Array<IntArray> = distances
fun optimize(): MutableList<Int> {
var bestSolution = mInitialSolution
var newSolution = mInitialSolution
var bestDistance = findTotalDistance(mDistances, bestSolution)
var i = 0
while (i <= 5) {
println("best distance at start of loop: $bestDistance")
var cityIndex1 = Integer.MAX_VALUE
var cityIndex2 = Integer.MAX_VALUE
while (cityIndex1 == cityIndex2) {
cityIndex1 = Random().nextInt(mInitialSolution.size)
cityIndex2 = Random().nextInt(mInitialSolution.size)
}
val temp = newSolution.get(cityIndex1)
newSolution.set(cityIndex1, newSolution.get(cityIndex2))
newSolution.set(cityIndex2, temp)
val newDistance: Int = findTotalDistance(mDistances, newSolution)
println("new distance: $newDistance\n")
if (newDistance < bestDistance) {
println("New values gived to solution and distance")
bestSolution = newSolution
bestDistance = newDistance
}
i++
}
println("The distance of the best solution ${findTotalDistance(mDistances, bestSolution)}")
return bestSolution
}
fun findTotalDistance(distances: Array<IntArray>, orderToBeVisited: MutableList<Int>): Int {
var totalDistance = 0
for (i in 0..orderToBeVisited.size - 2) {
val fromCityIndex = orderToBeVisited.get(i)
val toCityIndex = orderToBeVisited.get(i + 1)
totalDistance += distances[fromCityIndex].get(toCityIndex)
}
return totalDistance
}
}
Kotlin (and JVM languages in general) doesn't copy values unless you specifically ask it to. This means that, when you do this:
var bestSolution = mInitialSolution
var newSolution = mInitialSolution
You're not setting bestSolution and newSolution to separate copies of mInitialSolution, but rather making them point at same MutableList, so mutating one mutates the other. Which is to say: your problem isn't that bestSolution is getting overwritten, it's that you're accidentally modifying it every time you modify newSolution.
You then reuse newSolution for every iteration of your while loop without ever creating a new list. This leads us to two things:
Because newSolution still aliases bestSolution, modifying the former also modifies the latter.
bestSolution = newSolution doesn't do anything.
As mentioned in a comment, the easiest way to fix this is by making strategic use of .toMutableList(), which will force copying the list.You can achieve this by making this change at the top:
var bestSolution = mInitialSolution.toMutableList()
var newSolution = mInitialSolution.toMutableList()
Then inside the loop:
bestSolution = newSolution.toMutableList()
Incidentally: As a general rule, you should probably return and accept List rather than MutableList unless you specifically want it to be part of the contract of your function that you're going to mutate things in-place. In this particular case, It would've forced you to either do something icky (like unsafe-casting mInitialSolution to MutableList, which should sound all sorts of warning bells in your head), or copy the list (which would've nudged you towards the right answer)

Convert from char to operator Kotlin

Is there any way to convert a char, lets say with a value of '+', into the operator +? Something like this:
println(1 charOperator 1);
output:
2
You can use something like this:
fun operatorFromChar(charOperator: Char):(Int, Int)->Int
{
return when(charOperator)
{
'+'->{a,b->a+b}
'-'->{a,b->a-b}
'/'->{a,b->a/b}
'*'->{a,b->a*b}
else -> throw Exception("That's not a supported operator")
}
}
and later call:
println(operatorFromChar('+').invoke(1,1))
Operators are, at the end of the way, functions. If you return a function with the operator's job, you can invoke it as it was the operator itself, but it will never be as "pretty" as calling the operator directly.
This isn't really possible. Maybe you should add your current solution and there's another way to help you out.
Here's a sneaky solution for calculating expressions with + and - only:
val exp = "10+44-12+3"
val result = exp.replace("-", "+-").split("+").sumBy { it.toInt() }
You can do something like
infix fun Int.`_`(that: Int) = this + that
where the backtick is unnecessary to this character but maybe necessary for other character. Then you can try:
println(2 _ 3) // output: 5
Update according to the comment:
I mean something like
val expr = input.split(' ')
when (expr[1])
{
'+' -> return expr[0].toInt() + expr[2].toInt()
'-' -> return expr[0].toInt() - expr[2].toInt()
'*' -> return expr[0].toInt() * expr[2].toInt()
'/' -> return expr[0].toInt() / expr[2].toInt()
// add more branches
}
However, I was wondering whether there is a better and tricky solution from the grammar of Kotlin.
What you basically want is an Char to result of an operation mapping. So, I decided to return the result right away and not a lambda.
fun Int.doOperation(charOperator: Char, x: Int) = when(charOperator) {
'+' -> this + x
'-' -> this - x
'/' -> this / x
'*' -> this * x
else -> throw IllegalArgumentException("Not supported")
}
Using an extension function maybe (?) makes the syntax a little nicer. You decide.
Call site:
println(5.doOperation('+', 6))
You can use the interpreter class in beanshell library
to convert string text automatically to result
for example
interpreter.eval("equal=2*3")
println(interpreter.get("equal").toString().toDouble().toString())
or can use expression class that does the same thing
fun String.stringToConditionalOperators(): (Boolean, Boolean) -> Boolean {
return when (this.lowercase(Locale.getDefault())) {
"and" -> {
{ a: Boolean, b: Boolean ->
a && b
}
}
"or" -> {
{ a: Boolean, b: Boolean ->
a || b
}
}
// You can add more operator 🤩
else -> {
return { a: Boolean, b: Boolean ->
a || b
}
}
}
}
Usage..
val operator = "AND"
operator.stringToConditionalOperators().invoke(one, two)