Is it possible to use High order functions with optional arguments - kotlin

I put together a dummy problem to illustrate my point: Say that we have the following handy function to display information about a particular sorting algorithm:
fun sort(name: String, array: Array<Int>, sortingAlgorithm: (Array<Int>) -> Array<Int>) {
println(name)
sortingAlgorithm(array).forEach { print(" $it ") }
println()
}
You would use it like this:
sort("Selection Sort - Θ(n^2)", arrayOf(2, 3, 1), ::selectionSort)
And this works because the signature of selectionSort is simple: fun selectionSort(array: Array<Int>): Array<Int> {
But say I have another sorting algorithm with the following signature
fun quickSort(array: Array<Int>,
start: Int = 0,
end: Int = array.size - 1): Array<Int> {
The last two arguments are optional, so in theory you could call quickSort the same way you call selectionSort. That is to say, it stil respects the signature (Array<Int>) -> Array<Int> Right?
Unfortunately when I try to call sort("Quick Sort", arrayOf(2, 3, 1), ::quickSort) I get:
I think that the compiler isn't being smart enough to realise that those two arguments are optional. How can avoid this problem, other than overloading the sort method to accept a high order function with the signature ?

There is no avoiding this problem since it would contradict 2 corner stones of Kotlin type system:
1) Every expression has a type (strong typing)
2) The receiver side does not affect an expression's type (local inference)
For example if you could do that, the following would not to work, which is a simple refactoring of your example:
val algorithm = ::quickSort
sort("Quick Sort", arrayOf(2, 3, 1), algorithm)
Anyways, the sort("Quick Sort", { quickSort(unsorted) }) workaround is too simple for Kotlin developers to spend spend time on the problem.

Related

Generic transpose (or anything else really!) in Kotlin

Working on an Advent of Code puzzle I had found myself defining a function to transpose matrices of integers:
fun transpose(xs: Array<Array<Int>>): Array<Array<Int>> {
val cols = xs[0].size // 3
val rows = xs.size // 2
var ys = Array(cols) { Array(rows) { 0 } }
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
Turns out that in the following puzzle I also needed to transpose a matrix, but it wasn't a matrix of Ints, so i tried to generalize. In Haskell I would have had something of type
transpose :: [[a]] -> [[a]]
and to replicate that in Kotlin I tried the following:
fun transpose(xs: Array<Array<Any>>): Array<Array<Any>> {
val cols = xs[0].size
val rows = xs.size
var ys = Array(cols) { Array(rows) { Any() } } // maybe this is the problem?
for (i in 0..rows - 1) {
for (j in 0..cols - 1)
ys[j][i] = xs[i][j]
}
return ys
}
This seems ok but it isn't. In fact, when I try calling it on the original matrix of integers I get Type mismatch: inferred type is Array<Array<Int>> but Array<Array<Any>> was expected.
The thing is, I don't really understand this error message: I thought Any was a supertype of anything else?
Googling around I thought I understood that I should use some sort of type constraint syntax (sorry, not sure it's called like that in Kotlin), thus changing the type to fun <T: Any> transpose(xs: Array<Array<T>>): Array<Array<T>>, but then at the return line I get Type mismatch: inferred type is Array<Array<Any>> but Array<Array<T>> was expected
So my question is, how do I write a transpose matrix that works on any 2-dimensional array?
As you pointed out yourself, the line Array(cols) { Array(rows) { Any() } } creates an Array<Array<Any>>, so if you use it in your generic function, you won't be able to return it when Array<Array<T>> is expected.
Instead, you should make use of this lambda to directly provide the correct value for the correct index (instead of initializing to arbitrary values and replacing all of them):
inline fun <reified T> transpose(xs: Array<Array<T>>): Array<Array<T>> {
val cols = xs[0].size
val rows = xs.size
return Array(cols) { j ->
Array(rows) { i ->
xs[i][j]
}
}
}
I don't really understand this error message: I thought Any was a supertype of anything else?
This is because arrays in Kotlin are invariant in their element type. If you don't know about generic variance, it's about describing how the hierarchy of a generic type compares to the hierarchy of their type arguments.
For example, assume you have a type Foo<T>. Now, the fact that Int is a subtype of Any doesn't necessarily imply that Foo<Int> is a subtype of Foo<Any>. You can look up the jargon, but essentially you have 3 possibilities here:
We say that Foo is covariant in its type argument T if Foo<Int> is a subtype of Foo<Any> (Foo types "vary the same way" as T)
We say that Foo is contravariant in its type argument T if Foo<Int> is a supertype of Foo<Any> (Foo types "vary the opposite way" compared to T)
We say that Foo is invariant in its type argument T if none of the above can be said
Arrays in Kotlin are invariant. Kotlin's read-only List, however, is covariant in the type of its elements. This is why it's ok to assign a List<Int> to a variable of type List<Any> in Kotlin.

Compare value against two values with 'or' operator

I have a simple if () condition which needs to check if value is either 1 or 2 (for example). Let's say the value we are comparing against is not 'simple':
if(it.first().property.value == 1 || it.first().property.value == 2) {
// Do stuff
}
Is there a better way to perform this check (without typing the entire expression to get the actual value twice)? The only thing that comes to mind is
if(listOf(1, 2).contains(it.first().property.value)) {
// Do stuff
}
But I'm afraid it's more memory consuming since it has additional list introduced.
Your last suggestion is a good one in general, though it's usually better to use a predefined list (and the in operator):
// At the top level, or in a (companion) object:
val acceptableValues = listOf(1, 2)
// Then in the relevant part of the code:
if (it.first().property.value in acceptableValues)
// Do stuff
That only allocates the list once, and performance is about as good as any other option.  It's also very readable, and general.
(If the list doesn't naturally fit into a named property, you'd have to judge how often it might be needed, in order to trade a minor performance benefit against the conciseness of putting it directly in the condition.)
In fact, because you're looking for consecutive integers, there's a more concise option for this particular test:
if (it.first().property.value in 1..2)
// Do stuff
That would work whenever the acceptable values form an (uninterrupted) range.
Alternatively, if you're always checking against exactly two values, you could write a simple extension function:
fun <T> T.isEither(a: T, b: T) = this == a || this == b
(You could write a more general one using a vararg param, but that would create an array each time — very similar to the in listOf() case we started with.)
You can decide it using a when expression like in this example:
fun main() {
val number = 22
when (number) {
1, 2 -> println("${number} is 1 or 2")
in 10..20 -> println("${number} is between 10 and 20 (inclusively)")
else -> println("${number} is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above")
}
}
The output here is
22 is either negative, equals 0, 3, 4, 5, 6, 7, 8, 9, 21 or any number above
You could define an extension function on the type of it to make it more readable:
if(it.isOneOrTwo()) {
// Do stuff
}
Not sure what's the type of your it, replace TYPEOFIT accordingly:
private inline fun TYPEOFIT.isOneOrTwo() = first().property.value == 1 || first().property.value == 2
To additionally improve the condition you could leverage when:
private inline fun TYPEOFIT.isOneOrTwo() = when(first().property.value) {
1,2 -> true
else -> false
}

What's the point of destructuring declarations in Kotlin?

I have come across the concept called destructuring declarations - when you can return multiple values from a function at once. It seems very convenient, but at the same time it looks like a tricky workaround. Each time when I think about that feature in Java, I understand that it's a hole in my architecture - there should probably be a class then, not just a couple of variables.
What do you think?
The concept allows having classes that clearly identify a few of their primary properties, the components.
Then you can access these components by using a destructuring declaration, without syntactic noise of accessing the properties.
Compare:
val point = clickEvent.getPointOnScreen()
val x = point.xCoordinate
val y = point.yCoordinate
// Use `x` and `y` in some calculations
and, assuming that the type has component1 and component2, just:
val (x, y) = clickEvent.getPointOnScreen()
Basically, it is not necessary to use this sort of syntactic sugar, and the concept itself does not harm any of the abstractions, it only provides a convenient way to access properties of a class instance in some cases when you don't need the instance itself.
Another example is working with map entries, e.g:
for ((key, value) in myMap) { /* ... */ }
There's still a Map.Entry<K, V> behind the (key, value) destructuring, and you can replace it by for (entry in myMap) ..., but usually it's the two properties that you need. This is where destructuring saves you from a little syntactic noise.
You can also define componentN function as extension for non data classes like this:
operator fun Location.component1() = latitude
operator fun Location.component2() = longitude
and when you want to process on list of locations, you can write this:
for ((lat, lon) in locations) {
......
}
What's the point of destructuring declarations in Kotlin?
Structuring, or construction, is creating an object from values in different variables. Destructuring is the opposite, to extract values into variables from within an existing object.
Part of the Kotlin philosophy is to be concise since the simpler and more concise the code is, the faster you’ll understand what’s going on. Destructuring improves readability which is part of being concise. Compare the following two snippets (let's consider the class Triple)
Without using destructuring
fun getFullName() = Triple("Thomas", "Alva", "Edison")
val result = getFullName()
val first = result.first
val middle = result.second
val last = result.third
Using destructuring
fun getFullName() = Triple("Thomas", "Alva", "Edison")
val (first, middle, last) = getFullName()
It is also possible to take advantage of destructuring to extract key and value from Map's entries.
for ((key, value) in aMap) {
/* ... */
}
Destructuring is the most useful when dealing with built-in data structures. Their fields have names making sense in the context of a data structure (handy when you're writing your own hashmap), but completely cryptic when you're dealing with the data contained there (which is 100% of the time, nobody writes their own hashmaps). Eg. Pair with it's first and second or Map.Entry with key and value.
Consider transforming Map values:
val myMap = mapOf("apples" to 0, "oranges" to 1, "bananas" to 2)
myMap
.asIterable()
.filter { it.value > 0 }
.sortedBy { it.key.length }
.joinToString(prefix = "We have ", postfix = " in the warehouse") {
"{$it.value} of ${it.key}"
}
To make it readable, you'd have to define intermediate variables:
myMap
.asIterable()
.filter {
val count = it.value
count > 0
}
.sortedBy {
val fruit = it.key
fruit.length
}
.joinToString(prefix = "We have ", postfix = " in the warehouse") {
val count = it.value
val fruit = it.key
"$count of $fruit"
}
Now it's readable, but at what cost?!?
Destructuring makes this cost more beareable:
myMap
.asIterable()
.filter { (fruit, count) -> count > 0 }
.sortedBy { (fruit, count) -> fruit.length }
.joinToString(prefix = "We have ", postfix = " in the warehouse") { (fruit, count) ->
"$count of $fruit"
}
That's the point.

Kotlin methods with Vararg as First Parameter

Note I've looked at the following questions/answers to solve the problem without any luck. Call Java Varargs Method from Kotlin - this one has the varargs parmeter at the end of the parameter list, but my question deals with varargs at the start of the parameters list. Kotlin: Convert List to Java Varargs - the same. Other searches yield the same thing. These were the closest I could find.
I am calling the Kotlin String.split method with a single character delimiter.
This is a vararg method where the vararg parameter is first of multiple parameters. The method is defined like so:
public fun CharSequence.split(vararg delimiters: Char,
ignoreCase: Boolean = false,
limit: Int = 0): List<String>
When I call the method as below, it compiles fine:
fun String.splitRuleSymbol() : String = this.split(':') //ok
But when I try to add the ignoreCase and limit parameters, I get a problem:
fun String.splitRuleSymbol() : String = this.split(':', true, 2) //compiler error
The error I get is...
None of the following functions can be called with the arguments supplied:
public fun CharSequence.split(vararg delimiters: String, ignoreCase: Boolean = ..., limit: Int = ...): List defined in kotlin.text
public fun CharSequence.split(vararg delimiters: Char, ignoreCase: Boolean = ..., limit: Int = ...): List defined in kotlin.text
To me, having a vararg parameter followed by other parameters is somewhat odd, but that's beside the point. If I call it as below, it works fine:
// both of the following compile
fun String.splitRuleSymbol() : String =
this.split(delimiters = ':', ignoreCase = true, limit = 2)
fun String.splitRuleSymbol2() : String =
this.split(';', ignoreCase = true, limit = 2)
Is there a way to pass a vararg Char in to this method without having to qualify my other two parameters with parameter names ignoreCase and limit? Can the compiler not tell that the remaining parameters are not Char?
I have tried the spread operator and a few other ways below , none of which work:
//compiler errors on all these
this.split(*':', true, 2) //using the "spread" operator
this.split(*charArrayOf(':'), true, 2)
this.split(*mutableListOf(':'), true, 2)
this.split(*Array<Char>(1) { ':' }, true, 2)
Yes, some of these look ridiculous, I know. But, is there no way to avoid the verbose alternative?
PS As I was formulating my question, I found another expression that compiled.
this.split(':', limit = 2)
This is less verbose and since I don't need to change the default ignoreCase parameter, it's closer to what I am looking for.
Your observations are correct. Arguments that are after a vararg parameter can only ever be passed in by using named arguments, otherwise you'd run into ambiguity issues (for a trivial example, let's say when all arguments are of type Any).
The best source I can find for this right now is this book.
The vararg parameter is usually the last parameter, but it does not always have to be. If there are other parameters after vararg, then arguments must be passed in using named parameters
Edit: #Les found a good source on it, see their answer.
Thanks to zsmb13, I was able to find the following paragraph in the Kotlin Specification (under "Functions and Lambdas")
Only one parameter may be marked as vararg . If a vararg parameter is
not the last one in the list, values for the following parameters can
be passed using the named argument syntax, or, if the parameter has a
function type, by passing a lambda outside parentheses.
I would venture to add that "can be passed" should be changed to "must be passed" since the compiler won't allow otherwise.
Note The lambda part is interesting in that the spec normally only allows a lambda to be moved outside the parenthesis when it is the last parameter. The wording of the spec implies the lambda could be anywhere after the vararg parameter, but experimentation shows that it cannont, i.e., it must be the last parameter in order to be eligible to move outside of the parenthesis.
fun main(args: Array<String>) {
test("hello", limit = 1, ic = false, delims = ';') { } //ok
//test2("world", limit = 1, ic = false, delims = ';') { } //error
test2("world", f = {}, limit = 1, ic = false, delims = ';') //ok
test("hello world", ';', limit = 1, ic = false) {} //ok
}
fun test(vararg delims: Char, ic: Boolean, limit: Int, f: () -> Unit) {}
fun test2(vararg delims: Char, f: () -> Unit, ic: Boolean, limit: Int) {}
Variable number of arguments (vararg) can be passed in the named form by using the spread operator:
fun foo(vararg strings: String) { /* ... */ }
foo(strings = *arrayOf("a", "b", "c"))
foo(strings = "a") // Not required for a single value
Note that the named argument syntax cannot be used when calling Java functions, because Java bytecode does not always preserve names of function parameters.

Kotlin sequence concatenation

val seq1 = sequenceOf(1, 2, 3)
val seq2 = sequenceOf(5, 6, 7)
sequenceOf(seq1, seq2).flatten().forEach { ... }
That's how I'm doing sequence concatenation but I'm worrying that it's actually copying elements, whereas all I need is an iterator that uses elements from the iterables (seq1, seq2) I gave it.
Is there such a function?
Your code doesn't copy the sequence elements, and sequenceOf(seq1, seq2).flatten() actually does what you want: it generates a sequence that takes items first from seq1 and then, when seq1 finishes, from seq2.
Also, operator + is implemented in exactly this way, so you can just use it:
(seq1 + seq2).forEach { ... }
The source of the operator is as expected:
public operator fun <T> Sequence<T>.plus(elements: Sequence<T>): Sequence<T> {
return sequenceOf(this, elements).flatten()
}
You can take a look at the implementation of .flatten() in stdlib that uses FlatteningSequence, which actually switches over the original sequences' iterators. The implementation can change over time, but Sequence is intended to be as lazy as possible, so you can expect it to behave in a similar way.
Example:
val a = generateSequence(0) { it + 1 }
val b = sequenceOf(1, 2, 3)
(a + b).take(3).forEach { println(it) }
Here, copying the first sequence can never succeed since it's infinite, and iterating over (a + b) takes items one by one from a.
Note, however, that .flatten() is implemented in a different way for Iterable, and it does copy the elements. Find more about the differences between Iterable and Sequence here.
Something else you might need to do is create a sequence of sequences:
val xs = sequence {
yield(1)
yield(2)
}
val twoXs = sequence {
yieldAll(xs)
// ... interesting things here ...
yieldAll(xs)
}
This doesn't do anything that xs + xs doesn't do, but it gives you a place to do more complex things.