Kotlin utils


#1

I learning Kotlin in writing code on it. However I don’t find in std library some useful things for me. I made decision to create small library where I will store missing utilizes.

Summary of the kotlin-utils library:
Author: Alexander Kornilov
Version: 0.5
License: Apache v2.0
Project URL: https://bitbucket.org/akornilov/kotlin-utils
API documentation: https://akornilov.bitbucket.io/doc/kotlin-utils
Gradle dependency on Maven Central: compile ‘org.bitbucket.akornilov.kotlin:kotlin-utils:0.5’
Maven Central: https://repo.maven.apache.org/maven2/org/bitbucket/akornilov/kotlin/kotlin-utils/0.5/

It’s very tiny library yet and contains very simple things like:

  • String.Empty
  • Integer.repeat
    5.repeat {
    // Repeats 5 times where ‘it’ is index of iteration
    }
  • String formatter:
    val number = 0x33a
    println(“Number in hex: 0x${number[“08X”]}”)
    // prints to console: ‘Number in hex: 0x0000033A’
  • Slot/Signal model implementation.
  • Improvements for EnumSet.

#2

What’s the purpose of String.Empty? I believe all string literals are interned by kotlinc


#3

Also, marking all functions with inline will not improve performance but only make it worse.
In general, inline imporve performance only for higher order functions.
The main uses are: reifed generics and non-local returns. But even then, inline function should stay small.


#4

See String.isEmpty and repeat(Int)


#5

Maybe it just my habit from C#, but, think, I can give some reasons:

  1. val str1 = “”
    val str2 = “”
    No guaranty that str1 === str2
    But
    val str1 = String.Empty
    val str2 = String.Empty
    is sure str1 === str2
  2. val str1 = String.Empty is more expressive and expresses intention of code author than
    val str2 = “”

#6

Probably you just quoting the recommendations from “Kotlin in action” book :slight_smile:
I agree that it’s correct in general. But when you writing some kind of system library you should think about performance. And ‘inline’ is a powerful tool in optimization.
In a case where I doubt, I just do profiling.


#7

Sure enough I know about it :wink: String.Empty.isEmpty always.

I prefer function extension for kotlin.Int.


#8

Hello!

I have released ‘kotlin-utils’ v0.7

What news:

  • Migrate to Kotlin v1.3.0

  • New extension for Collections.oneOrNull() - returns single value of collection or null for collection with size not equals one (e.g. empty collection).

  • Property delegate for Comparable value (e.g. Int, Long) - PropertyRange.
    This can be helpful when you want to keep you integer property in the specified range or e.g. only positive.
    val number1: Int by PropertyRange(5, 3…7)
    In this example 5 is initial value and 3…7 is valid range for property number1.
    Also, you can choose behavior on range violation.
    By default, if a new value less than minimal range value it silently changed to minimal and same rule for a maximum edge.
    number1 = 10 // in fact will be 7
    number1 = -100 // in fact will be 3

But you can write your own violation handler or pass second existing handler which throws IllegalArgumentException: exceptionViolation()
val number2: Int by PropertyRange(0, 0) // Only minimal edge set — zero, so this one only for positive values.
val number3: Long by PropertyRange(-7, max = 128) // Only maximum edge set — max value is 128.

  • Property delegate to cache mutable value.
    E.g. you have some mutable list and you want to have a property which contains the actual sum of the list:
    val list = mutableListOf(1, 2, 3)
    val sumOfList by CachedProperty(list) {
    sum() // ‘this’ in this block is monitored object ie list.
    }

On the first access, the code block with sum() will be called and the result of the operation will be stored in the property.
Also, hashCode of the list will be stored in the property.
On the second access, if the list was not changed ie hashCode is still equaled with stored in property just cached value will be returned. Ie code block with sum() will not be called.
In addition, you can implement your own logic of tracking an object without using of hashCode.
For immutable objects, you can use a hint for CachedProperty and it will be like lazy() delegate.

  • Implementation of the Graph operations.

    • Parametrized value of each vertex.
    • Parametrized value of each edge.
    • Simple navigation inside the graph by vertexes or edges.
    • Edges with mutable weight.
    • Customization of the edge by implementing AbstractEdge interface.
    • Separate interfaces for mutable and immutable graphs.
    • Main analytic operations on graphs.
    • Topological sort.
    • The fast check of reachability for any pairs of vertexes within the graph.
    • Founds an optimal path between any pairs of vertexes. Dynamic information about edges weight taken into account on each request.
    • Cache for search requests to increase performance.
    • Founds all possible paths from specified vertex to another sorted by total path weight.

Example of a topological sort for the graph (see attached picture):
val analyst = analystOf(edge(“A”, “B”, 1),
edge(“A”, “C”, 2),
edge(“B”, “C”, 3),
edge(“B”, “D”, 4),
edge(“C”, “E”, 5),
edge(“E”, “D”, 6),
edge(“C”, “F”, 7),
edge(“F”, “E”, 8),
edge(“G”, “A”, 9),
edge(“G”, “F”, 10))

analyst.sortTopological()

Result is: “G”, “A”, “B”, “C”, “F”, “E”, “D”


#9

Then why are many functions in the stslib marked as inline (with kotlin.internal.InlineOnly`)?


#10

Because tiny function which might be called often is an ideal candidate to inline, especially in the stdlib.
It improves performance at the cost of increasing class files size.
On the over hand, do inline by hand we take a “bread” away from JIT (in case we talking about JVM target).
“You probably know that the JIT will try to inline frequently called methods in order to avoid the overhead of method invocation.”
https://techblug.wordpress.com/2013/08/19/java-jit-compiler-inlining/


#11

There are quite some functions in kotlin-stdlib that do not take lambda parameters but still have the inline modifier. Sometimes it looks inconsistent inside the stdlib source.


#12

To inline of tiny function improve performance regardless of high order function as a parameter. And developers of Kotlin stdlib understand that enough.
Probably because they spend some time in profiling.


#13

Not on Android


#14

One more argument for multiple using inline in stdlib - nuances of JVM/JIT implementation on different platforms.


#15

If it is really a trivial function then inline will always be an improvement (for example a forward to a differently named function, or different overload).


#16

What are the advantages of using this instead of singleOrNull() from the stdlib?


#17

Ups… :slight_smile: Thank you!
I haven’t been paying very close stdlib. Will be removed.