What is the difference in these way of creating a list in Kotlin ? My result1 is valid but result2 is invalid - kotlin

val list1 = listOf(1,2,3,4,5,6,7,8,9)
val list2 = listOf(1..9)
/*
my result1 is valid but result2 gives error
*/
val result1= list1.filter{i -> i>2}
val result2 = list2.filter{i -> i>2}

listOf(1, 2, 3, 4, 5, 6, 7, 8, 9)
is a list of nine numbers — specifically, Ints.
However, 1..9 is a range object — specifically, an IntRange.  So:
listOf(1..9)
is a list that contains a single object.
list1.filter{ i -> i > 2 }
is valid, because filter() applies its lambda to each Int in the list — and the > operator is defined between two Ints.  However:
list2.filter{ i -> i > 2 }
is not valid, because the lambda is applied to the IntRange, and you can't compare an IntRange to an Int.
Your IDE and compiler should give you several clues about this.  First, if you hover over list1 and list2 you'll see the types that the compiler infers for them: List<Int> and List<IntRange>, respectively.
And not only does the IDE underline { i -> i > 2 }, it also shows the > in red.  Hovering over that shows the error ‘Unresolved reference. None of the following candidates is applicable because of receiver type mismatch…’  That's a bit cryptic, but you should get to know it, because it's quite common and very useful.  It's telling you that you're trying to call a function/method/operator that's not defined for the type(s) you have.  In this case, > (which is equivalent to compareTo()) is defined for two Ints, two Longs, two Strings, etc., but not for an IntRange and an Int.
So the compiler doesn't know what return type it should have, and temporarily assumes Unit — but filter() needs a lambda returning a Boolean, which is why the whole lambda is underlined with a ‘Type mismatch’ error.
As Tenfour04 says, you can convert a range into a list if you need to (using the toList() method).  But in practice, that's not needed very often because there's usually a better approach.  (A range takes much less memory than most lists, and is therefore quicker to iterate through; and it implements Iterable so you can already do most list-type things with it anyway.)

Related

How to prevent implicit generalization casts when using generic types in Kotlin? [duplicate]

This question already has an answer here:
Force type parameter to be invariant at use-site when it is covariant at declaration site
(1 answer)
Closed 1 year ago.
Minimal example:
fun <T> Iterable<T>.find2(elem: T) = this.find { it == elem }
Here, T is used to both denote the type of the Iterable, as well as the type of elem. It seems fine, however, a statement like this is syntactically correct, but doesn't make semantic sense:
listOf(1, 2, 3).find2("foo")
I assume this works because T resolves to Any.
I'm aware of the solution to explicitly state the type of the function:
listOf(1, 2, 3).find2<Int>("foo")
In this case, the compiler reports an incompatibility error, and rightfully so. However, this doesn't seem to be the solution, since it requires to explicitly declare the type, and will not report an error if forgotten (which makes bugs likely).
Is there a way to "constrict" the type <T>, so that, if, for example, the receiver is of type Iterable<Int>, the parameter must also be Int? In other words, is there a way to prevent the implicit cast to Any?
In the statement
listOf(1, 2, 3).find2("foo")
There are actually two types that need to be resolved,
T1 in listOf<T1> and T2 in Iterable<T2>.find2,
and have the following constraints
T1 is the same as T2, because listOf returns List<T1>, which is Iterable<T2>, for find2
1, 2 and 3 should be assignable to T1
"foo" should be assignable to T2
Therefore, the type has to be Any.
We usually explicitly declare the type of the list since it is the source,
listOf<Int>(1, 2, 3).find2("foo")
Or separate it into two statements
val listOfInt = listOf(1, 2, 3)
listOfInt.find2("foo")

Kotlin destructuring more than five components

I have the result of a regex that returns seven capturing groups into an array.
Rather than using the subscript of the array elements to construct my object I thought I would use destructuring, the problem is it seems I can only have five components.
A minimal example:
// val (a, b, c, d, e) = listOf(1, 2, 3, 4, 5)
val (a, b, c, d, e, f, g) = listOf(1, 2, 3, 4, 5, 6, 7)
Compiler output:
> Error:(70, 41) Kotlin: Destructuring declaration initializer of type
> List<Int> must have a 'component6()' function
> Error:(70, 41) Kotlin: Destructuring declaration initializer of type
> List<Int> must have a 'component7()' function
Is there a way to have more than five components or is this the max?
There are only 5 component functions defined for the List interface (as extension functions).
You can add your own component functions as extension functions:
operator fun <T> List<T>.component6() = this[5]
operator fun <T> List<T>.component7() = this[6]
// ...
This would work now:
val (a, b, c, d, e, f, g) = listOf(1, 2, 3, 4, 5, 6, 7)
From the docs:
And, of course, there can be component3() and component4() and so on.
Note that the componentN() functions need to be marked with the
operator keyword to allow using them in a destructuring declaration.
Kotlin defines extension methods for these component destructors. Unlike data classes, these aren't generated infinitely with one for each item. It also makes them slightly dangerous, which I'll get back to later.
For reference, the definition is here, and the KDoc can be found here (search for component in the list. For easy access, here's component1).
As you can see in the source definition (and documentation for that matter, but the source makes it more visible), there are only 5 methods (component1 to component5), each of which call get(n - 1), where n is the ID of the component destructor.
If you want more, you'll have to define them yourself, in the pattern of:
inline operator fun <T> List<T>.componentN(): T {
return get(N - 1)
}
(or in the style suggested in the other answer - they produce the same results.)
And again, where N is 6 and up, matching the amount of items you plan on having.
However, I wouldn't recommend this. It's much easier iterating over it with a for loop, and it's also less prone to error. Take for an instance this:
val (a, b, c, d, e) = listOf(1, 2, 3, 4)
That will throw an ArrayIndexOutOfBoundsException. If, however, you have a static list (and know what you're doing), destructing with componentN is safe. Although if you have a mostly static list where you want future flexibility, you can use a data class. Those also generate the componentN functions for you, and limit themselves to the amount of fields you actually have - which means no exceptions at runtime, but instead compiler errors.
If you use lists to enable iteration in addition to destruction, you can also take the alternative approach and define an operator fun iterator and return a list of the items.

Why should I assign the data type of variables in Kotlin if giving it values initially it is capable of inferring the data type of the variable

As mentioned in the code provided. My question is if there is any advantage by mentioning the data type early on when I am just giving the variable it's value. As said in line 2 it can understand that it is int type.
val a: Int = 1 // immediate assignment
val b = 2 // `Int` type is inferred
val c: Int // Type required when no initializer is provided.
A few reasons you might want to specify a type explicitly:
You want a supertype of the value (perhaps so you can to reassign it later), e.g.:
var myList: List<String> = ArrayList<String>()
You want to protect against changes to other code (especially if it's outside your control), e.g.:
val x: MustBeThisType = SomeLibrary.getValue()
(That would give an error if SomeLibrary.getValue() ever changes to returns something other than MustBeThisType or a subtype.)
You want to avoid an explicit numeric conversion, e.g.:
val x: Long = 2
instead of:
val x = 2.toLong()
You want to make it very clear to someone reading your code (especially if that might not be in an IDE).
As Michael says, you may need to specify the nullability of types returned from Java, e.g.:
val x: String = someJavaClass.getAString() // Never returns null
None of those is particularly common in my experience, though.

Cast Any to Array in Kotlin

I'm initializing a class by loading data from a Map<String, Any> in Kotlin. As this Map is gleaned directly from JSON, I don't know for certain that any given key exists, or that its value is of the type I expect. To unpack this Map safely I'm doing the following, which appears to work perfectly:
a = rawData["A"] as? String ?: ""
Some of this data is in further nested JSON, which I'm unpacking to Arrays; I've tried to do this in the same way:
b = rawData["B"] as? Array<String> ?: arrayOf<String>()
However, when I attempt this using an array (as above) IntelliJ kicks up a fuss, saying
Warning:(111, 30) Kotlin: Unchecked cast: Any? to Array<String>
Is this just the IDE getting itself in a twist or is this method genuinely unsafe for Arrays despite being seemingly perfectly safe for other types?
For any future readers of this question, to expand on the accepted answer with a solution:
To safely cast Any to an array of a particular type in Kotlin, you have to first cast to an untyped array (see zsmb13's answer above for why), and then filter that array to the desired type.
For example, to cast input: Any to an array of String instances, you would call:
val inputAsArray = (input as? Array<*>)?.filterIsInstance<String>()
I was ready to call this a bug, because Array is a reified type, meaning its generic parameter can actually be checked at runtime (unlike a List, for example). I've tried looking to see if it's been filed yet, and it turns out the compiler is actually right to show you a warning. As you can see in the response to this issue, there's still a nullability problem with casts of this kind.
val a = arrayOf("foo", "bar", null) as Array<String>
println(a[2].length)
Arrays like the one in this example are successfully cast (using as, they don't throw an exception, using as?, they don't return null), however, the cast can not ensure that this is an Array<String>, only that it's an Array<String?>.
This means that you can later read null values from a variable that is typed as an Array<String> after the cast, with no further warnings from the compiler.

Kotlin: What do the unary plus/minus operators do on numbers?

I've noticed in Kotlin that there are already defined unaryPlus and unaryMinus operators on all of the number types.
What's the purpose of these operators? Are they in some way connected to the prefix forms of inc and dec?
Others have defined the basic meaning of unaryMinus and unaryPlus, and in reality on numeric types they may not actually even be called as functions. For example, coding +x or x.unaryPlus() generates the same bytecode (where x is type Int):
ILOAD 1
ISTORE 2
And the code -x or x.unaryMinus() generates the identical bytecode:
ILOAD 1
INEG
ISTORE 2
But there is more going on that this...
So why does the compiler even generate anything for +x? Some people will say that +x and x.unaryPlus() doesn't do anything, and that -x and x.unaryMinus() only reverses the sign. That isn't correct. In Java it is more complicated because it can involve widening and unboxing, see Unary Numeric Promotion which explains the full consequences of these operators. This has consequences for boxed values and types smaller than Int. For value of type Short and Byte these operators will return a new unboxed value widened of type Int. And since both operators have this more hidden functionality then both must generate bytecode even if you don't think +x does anything. By the way, this is similar to what C language does and it is called Usual Arithmetic Conversions.
Therefore this code is invalid:
val x: Short = 1
val y1: Short = +x // incompatible types
val y2: Short = x.unaryPlus() // incompatible types
val z1: Short = -x // incompatible types
val z2: Short = x.unaryMinus() // incompatible types
In these numeric cases on the base numeric types they are just compiler magic to allow for the idea of these operators to be equated to operator functions that you might want to overload in other classes.
For other uses such as Operator Overloading...
But they are there for more than just mathematical use and can be used on any class as an operator. Kotlin exposes operators as functions so that you can apply operator overloading on a specific set of operators which include unaryMinus and unaryPlus.
I could use these to define operators for my own or existing classes. For example I have a Set<Things> where Things is an enum class along with an unaryMinus() operator to negate the contents of the finite set of options:
enum class Things {
ONE, TWO, THREE, FOUR, FIVE
}
operator fun Set<Things>.unaryMinus() = Things.values().toSet().minus(this)
And then I can negate my enum set whenever I want:
val current = setOf(Things.THREE, Things.FIVE)
println(-current) // [ONE, TWO, FOUR]
println(-(-current)) // [THREE, FIVE]
Notice that I had to declare my extension function with the modifier operator or this will not work. The compiler will remind you if you forget this when you try to use the operator:
Error:(y, x) Kotlin: 'operator' modifier is required on 'unaryMinus' in 'com.my.favorite.package.SomeClass'
These operators are the signs of the integers. Here are some examples:
+5 calls 5.unaryPlus() and returns 5.
-5 calls 5.unaryMinus() and returns -5.
-(-5) calls 5.unaryMinus().unaryMinus() and returns 5.
The purpose of those operators is to be able to write:
val a = System.nanoTime()
val b = -a // a.unaryMinus()
val c = +b // b.unaryPlus()
They are not directly related to ++/inc and --/dec operators however they can be used in conjunction.
Notice that the following expressions are different:
--a // a = a.dec()
-(-a) // a.unaryMinus().unaryMinus()
fun main(){
var a = 34
var b = 56
println("Orignal value:"+ a)
println("Orignal value:"+ b
//The value will not change using .unaryPlus() will generate bytecode
println("After unary plus:" + a.unaryPlus())
//The value will invert the sign using .unaryMinus() will generate bytecode
println("After unary minus:" + b.unaryMinus())
}
Solution:
Orignal value:34
Orignal value:56
After unary plus:35
After unary minus:-55