Kotlin showing error when I use I do Any as Int<Int - kotlin

I want to compare fields of a JSONObject.
Here is the code I am trying:
x = JSONObject()
x.put("num",1)
if(x["num"] as Int < 2){
print("Good work!")
}
Error shown by IDE:
Type expected
Expecting a '>

You need to put x["num"] as Int into parenthesis, otherwise the compiler will think that you are trying to do Int < 2 which doesn't really make any sense.
val x = JSONObject()
x.put("num", 1)
if ((x["num"] as Int) < 2) {
print("Good work!")
}
But btw, this will throw a ClassCastException if the value is not actually an Int. It is in your minimal case, but you don't always actually know. In that scenario I would do something like this:
val x = JSONObject()
x.put("num", "b")
val num = x["num"]
if (num is Int && num < 2) {
print("Good work!")
}

The current code doesn't work as-is because the compiler sees Int<42 and thinks that you're trying to use a type parameter for the Int type (like Int<T>) which obviously doesn't work for 2 reasons:
Type expected because 42 is not a type
Expecting a '>' because well, there is no >
As #Alex.T said, you can disambiguate this by putting (..) around the cast expression: (x["num"] as Int) < 2.
However, if you're OK with your expression failing at runtime like this, you should instead use a typed getter like getInt():
val x = JSONObject()
x.put("num", 1)
if (x.getInt("num") < 2) {
print("Good work!")
}
If the value is not an integer, this will fail at runtime with org.json.JSONException (as mentioned in the Javadoc linked above). You can catch this exception if you want to handle the error gracefully.
Alternatively you can use a safer option with a default value, like optInt(), which will default to the given value if the key is not present in the JSON OR if the value is not a number.

Related

Type mismatch: inferred type is unit but int is expected kotlin

Im trying to get multiple types of return (Int and Boolean) but i can only seem to get one at a time:
fun isValidPositions(p1: Int, p2: Int, pairs: List<Char>):Boolean{
if(p1 !in 0..9 || p2 !in 0..9 ){
println("Posições inválidas")
}else if (p1 == p2){
println("Posições inválidas")
}else if(pairs.get(p1) != '_' || pairs.get(p2) != '_' )
println("Posições inválidas")
return true
}
then in my funcion main i have this:
val first = readPosition("primeira")
val second = readPosition("segunda")
if ( isValidPositions(first, second, places) ) {
places = places.play(first, second, pairs)
and it gives me the error: Type mismatch: inferred type is unit but int is expected
i cant seem to understand how i can get 2 types of return when i need the true and an int
im really new to coding since i just got into uni
Your problem is most likely that readPosition doesn't return anything (in Kotlin, that means returning Unit). This means that you're assigning Unit to your first and second variables instead of the Int value you're expecting.
Then when you reach isValidPositions, it wants an Int but you're passing Unit.
You should post your readPosition function to get more help on this.

Kotlin - Type mismatch: inferred type is Any? but Boolean was expected

I'm trying my hands on Kotlin. Being from a Python background is really giving me a tough time to get the knack of the Kotlin syntax. I'm trying to do a simple dictionary (Mutable Map) operation. However, its giving me exceptions.
This is what I tried. Kotlin compiler
Adding the code snippet for reference.
fun main() {
val openActivityMap = mutableMapOf<String, MutableMap<String, Any>>()
val packageName = "amazon"
val currentTime = 23454321234
if(openActivityMap.containsKey(packageName)){
if(openActivityMap[packageName]?.get("isAlreadyApplied")){
if((openActivityMap[packageName]?.get("lastAppliedAt") - currentTime) > 3600){
openActivityMap[packageName]?.put("isAlreadyApplied", false)
}
}
else{
openActivityMap[packageName]?.put("isAlreadyApplied", false)
}
}
}
I'm a bit late to the party, but I'd like to point out another solution here.
As I commented on the OP, heterogeneous maps with fixed string keys like this are usually better expressed with classes in Kotlin. For instance, in your case, the class for your main map's values could be the following:
data class PackageInfo(
var isAlreadyApplied: Boolean,
var lastAppliedAt: Long,
)
(you could obviously add more properties if need be)
This would save you all the casts on the final values.
Another point I'd like to make is that if you access the value for a key anyway, you don't need to check up front the existence of the key with containsKey. Maps return null for keys that are not associated with any value (this is why you need to check for null after getting the value).
The compiler cannot see the correlation between containsKey and the subsequent get or [] access. However, it's smart enough to understand a null check if you simply get the value first and then check for null.
This always applies unless you want to tell the difference between keys that aren't in the map and keys that are in the map but associated null values (which is quite rare).
All in all, I would write something like that:
fun main() {
val openActivityMap = mutableMapOf<String, PackageInfo>()
val packageName = "amazon"
val currentTime = 23454321234
val packageInfo = openActivityMap[packageName]
if (packageInfo != null) { // the key was found and the value is smart cast to non-null in the next block
if (packageInfo.isAlreadyApplied) {
if ((packageInfo.lastAppliedAt - currentTime) > 3600) {
packageInfo.isAlreadyApplied = false
}
} else {
packageInfo.isAlreadyApplied = false
}
}
}
data class PackageInfo(
var isAlreadyApplied: Boolean,
var lastAppliedAt: Long,
)
I would recommend writing tests first and working in small increments, but this should fix your compilation issues:
fun main() {
val openActivityMap = mutableMapOf<String, MutableMap<String, Any>>()
val packageName = "amazon"
val currentTime = 23454321234
if(openActivityMap.containsKey(packageName)){
if(openActivityMap[packageName]?.get("isAlreadyApplied") as Boolean){
if((openActivityMap[packageName]?.get("lastAppliedAt") as Long - currentTime) > 3600){
openActivityMap[packageName]?.put("isAlreadyApplied", false)
}
}
else {
openActivityMap[packageName]?.put("isAlreadyApplied", false)
}
}
}
EDIT: Also I prefer to avoid nullable variables and mutable objects in general, but I suppose there's an exception to every rule.
Couldn't you just declare your Map<String, Any> to return a Boolean instead of Any? So,
val openActivityMap = mutableMapOf<String, MutableMap<String, Boolean>>()
It looks like you're trying to use your second Map to store both Booleans and Ints, which is complicating the logic. You'll need to typecast if you decide to approach it without Typing.
There's a problem with the 2 statement below
if(openActivityMap[packageName]?.get("isAlreadyApplied"))
if((openActivityMap[packageName]?.get("lastAppliedAt") - currentTime) > 3600)
As we all know, an IF statement requires a boolean value for it's param. The types of both statement are unknown at compilation time as they are of a Generic type, Any. As such,
openActivityMap[packageName]?.get("isAlreadyApplied") could be a null or of type Any (Not Boolean).
openActivityMap[packageName]?.get("lastAppliedAt") could be a null or of type Any (an Int was expected here for computation).
This would throw compilation errors as the compiler does not know the types to go with. What could be done is to cast to it's proper types.
Solution
openActivityMap[packageName]?.get("isAlreadyApplied") as Boolean ?: false
((openActivityMap[packageName]?.get("lastAppliedAt") as Int ?: 0) - currentTime)
Giving a default value if it's null.
maybe you can try something like this
if (openActivityMap.containsKey(packageName)) {
val packageMap = openActivityMap[packageName]!!
val applyRequired = (packageMap["lastAppliedAt"] as Long - currentTime) > 3600
packageMap["isAlreadyApplied"] = packageMap.containsKey("isAlreadyApplied") && !applyRequired
}
btw. do you really want to have lastAppliedAt to be in te future? otherewise it will never be > 3600

Input out of range for Int datatype, not passing a testcase

I am trying to solve the following question on LeetCode; Write a function that takes an unsigned integer and returns the number of '1' bits it has. Constraints: The input must be a binary string of length 32.
I have written the following code for that which works fine for inputs 00000000000000000000000000001011 and 00000000000000000000000010000000 (provided internally by the website) but give output 0 for input 11111111111111111111111111111101 and in my local compiler for the last input it says "out of range"
class Solution {
// you need treat n as an unsigned value
fun hammingWeight(n:Int):Int {
var num = n
var setCountBit = 0
while (num > 0) {
setCountBit++
num= num and num-1
}
return setCountBit
}
}
To correctly convert binary string to Int and avoid "out of range error", you need to do the following (I believe LeetCode does the same under the hood):
fun binaryStringToInt(s: String): Int = s.toUInt(radix = 2).toInt()
"11111111111111111111111111111101" is equivalent to 4294967293. This is greater than Int.MAX_VALUE, so it will be represented as negative number after .toInt() convertion (-3 in this case).
Actually, this problem could be solved with one-liner in Kotlin 1.4:
fun hammingWeight(n: Int): Int = n.countOneBits()
But LeetCode uses Kotlin 1.3.10, so you need to adjust your solution to handle negative Ints as well.
Please change the type of your input variable from Int to a type like Double .At the moment The given value is bigger than the maximum value that a type Int number can store.

Kotlin's logical 'and' doesn't short-circuit?

I was following along Kotlin's documentation at http://kotlinlang.org/docs/reference/null-safety.html#checking-for-null-in-conditions and tried adapting this example,
val b = "Kotlin"
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
to the case where b = null. In an IntelliJ Idea Kotlin project I have an app.kt with a main() function defined as:
fun main() {
val b = null
if (b != null && b.length > 0) {
print("String of length ${b.length}")
} else {
print("Empty string")
}
}
However, when I run this, I get two compilation errors:
Information:Kotlin: kotlinc-jvm 1.3.20 (JRE 11+28)
Information:2019-02-02 15:07 - Compilation completed with 2 errors and 0 warnings in 1 s 921 ms
/Users/kurtpeek/IdeaProjects/HelloWorld/src/app.kt
Error:(3, 24) Kotlin: Unresolved reference: length
Error:(4, 37) Kotlin: Unresolved reference: length
I understand that the compiler is evaluating b.length even though the first condition, b != null, is false. This surprises me because I thought that the first check was to 'short-circuit' the Boolean expression if needed and make the call to b.length 'safe'.
For example, in Python, you can do this:
In [1]: "foo" == "bar" and what.the.heck
Out[1]: False
which works even though what is not defined, because the and 'stops' since "foo" is not equal to "bar".
Is this indeed how Kotlin works? It seems like missing Python's 'short-circuiting' feature would be a limitation.
Kotlin's && operator will short circuit (just like Java's) but only at runtime. What you are experiencing is a compile time error. The big difference to remember especially when comparing Kotlin (or Java) to Python is that Kotlin and Java are statically typed and have a compilation phase. So you'll get a compilation error if the types don't match up.
Let's go through these one at a time...
val b = "Kotlin"
if (b != null && b.length > 0) {
...
}
In this case, Kotlin will correctly infer that b is the type String, because you clearly set it to a String ("Kotlin"). We should note here that the String type cannot ever contain null. Knowing that, the b != null part of your if statement is unnecessary. However, after evaluating that (to true, always) it will evaluate b.length because b is a String and therefore has a length property. This example should compile fine (I didn't test it).
And next...
val b = null
if (b != null && b.length > 0) {
...
}
This code will not compile, let's go over why...
This code looks really similar but has one huge difference. In this case because you just set b to null, Kotlin is going to infer that b is an Nothing?. It has no information as to what type you want b to be, and you've set it to null (and because it's a val, it will always be null). Because b is null, it makes b nullable.
So, given that, when we compile b != null, that will always fail, because b can't ever be something that isn't null. But wait! We're compiling now... and when we run into b.length Kotlin will throw a compilation error because Nothing? does not have a length property!
Essentially, by setting b to null and not providing a type hint, Kotlin takes the only path it can to infer the type - Nothing?.
From your linked text: "Note that this only works where b is immutable (i.e. a local variable which is not modified between the check and the usage or a member val which has a backing field and is not overridable)".
val b=null is immutable, but since the type of null cannot be inferred nor stored, it cannot be used as the source in a valid shortcut.
If you changed to code to give it a nullable type, and set that null, this would work.

Kotlin null safety?

Let's have a function foo and a class Bar:
fun foo(key: String): String? {
// returns string or null
}
class Bar(x: String, y: String) {
// ...
}
Now, let's have the code:
val x = foo("x")
val y = foo("y")
if (x.isNotEmpty() && y.isNotEmpty())
return Bar(x, y)
The problem is that this code will not compile. Since it needs the Bar(x!!, y!!).
However when I replace the function with its content, !! are not needed.
val x = foo("x")
val y = foo("y")
if ((x != null && x.length() > 0) && (y != null && y.length() > 0))
return Bar(x, y)
Why it is not possible to resolve the null check from the function .isNotEmpty()?
This is possible in theory, but it would mean that either
1. The declaration of isNotEmpty() must convey to the compiler the fact that x is guaranteed to be non-null if the result is true
2. A change to a body of any function may cause its call sites to fail to compile.
Option 2 is definitely unacceptable. Option 1 requires a rather expressive mechanism in the type system, which we decided not to add at the moment, because it is likely to complicate things for the user.
We are planning to support something like this with inline functions, but it's still under consideration.