I'm working on calculator project but when I tried to use two similar ways of comparing double and int numbers I got different results.
So my question is Why are these ways of comparing works differently?
//some code that parse the string
//...
//code of calculating:
fun calculateIn(queueNumbers: Queue<Double>, queueActions: Queue<Char>) {
var action: Char
var result = queueNumbers.poll()
var operand: Double
while (!queueNumbers.isEmpty()) {
operand = queueNumbers.poll()
action = queueActions.poll()
when (action) {
'-' -> result -= operand
'+' -> result += operand
'*' -> result *= operand
'/' -> result /= operand
'%' -> result = result % operand * -1.0
}
}
var pointNum = 8.3
println("pointNum = " + pointNum)
println(if(pointNum.compareTo(pointNum.toInt()) == 0) pointNum.toInt() else pointNum)
println("result = " + result)
println(if(result.compareTo(result.toInt()) == 0) result.toInt() else result)
}
Result of code:
"10.3 + -2" //input String
[10.3, -2.0] //queueNumbers
[+]//queueActions
pointNum = 8.3
8.3
result = 8.3
8
I think that is strange because if I run similar code I will get the correct result:
var pointNum = 8.3
println(if(pointNum.compareTo(pointNum.toInt()) == 0) pointNum.toInt() else pointNum)
So there is result of this code:
8.3
Full code on GitHub: https://github.com/Trilgon/LearningKotlin
I believe this is a bug in the compiler. Discussion is here, I copy my findings:
Minimal reproducible example:
fun test1(): Int {
val d: Double?
d = 8.3
return d.compareTo(8) // 0
}
fun test2(): Int {
val d: Double
d = 8.3
return d.compareTo(8) // 1
}
Technical difference between these two code samples is that the value is boxed in test1() and unboxed in test2(). If we look at the generated bytecode for test2(), everything looks as expected:
7: bipush 8
9: i2d
10: invokestatic #63 // Method java/lang/Double.compare:(DD)I
It converts integer value 8 to double and then compares both values as doubles.
But if we look into test1(), something bizarre happens there:
10: invokevirtual #52 // Method java/lang/Double.doubleValue:()D
13: d2i
14: bipush 8
16: invokestatic #58 // Method kotlin/jvm/internal/Intrinsics.compare:(II)I
It does the opposite: it converts double value 8.3 to integer and then compares values as integers. This is why it says values are the same.
What is interesting, even "Kotlin Bytecode" tool in IntelliJ shows the correct code for test1():
INVOKEVIRTUAL java/lang/Double.doubleValue ()D
BIPUSH 8
I2D
INVOKESTATIC java/lang/Double.compare (DD)I
But the real generated bytecode is different and gives different results.
I reported the problem: https://youtrack.jetbrains.com/issue/KT-52163
This was a weird and even funny problem to me, But I think I found out what's the problem.
In Kotlin Double class is defined inside Primitives.kt, well at least in the build-in files not in the actual source. Here Double class implements an interface named Comparable<Double> which is another built-in Kotlin file. You can see a portion of that interface:
public operator fun compareTo(other: T): Int
So let's return to your code. I suspend culprit of this problem is the very first line.
import java.util.*
Inside the java.util package there is another Comparable interface, I think since Queue is a Java class and the poll method may return a nullable value, and since you already imported everything inside java.util package then compareTo is called from Comparable from java.util not the one in Kotlin package.
The reason why Java's compareTo returns a different result is unknown to me.
I tried replacing java.util.* with:
import java.util.Queue
import java.util.LinkedList
But nothing changed.
However, I found another solution, just replace var result = queueNumbers.poll() with var result = queueNumbers.poll() ?: 0.0 or var result: Double = queueNumbers.poll() then it would be fixed!
//original
var result = queueNumbers.poll()
//method 1
var result : Double = queueNumbers.poll()
//method 2
var result = queueNumbers.poll() ?: 0.0
Related
I am trying to find the find the result of num1 raised to the power num2:
This is my code ->
fun power(num1 : Int, num2: Int): Int {
var result = 1
while (num2 != 0) {
return result *= num1
num2--
}
}
But the above code is producing the following error -->
Calculator.kt:30:16: error: assignments are not expressions, and only expressions are allowed in this context
return result *= num1
^
Calculator.kt:33:5: error: a 'return' expression required in a function with a block body ('{...}')
}
^
I have read a number of articles but not able to understand. Any help will be highly appreciated.
Thank you
An expression is something that evaluates to a value. An assignment is something that assigns a value to a variable or property.
x *= y is an assignment that is shorthand for x = x * y.
You cannot return an assignment, because it does not evaluate to a value. An assignment contains an expression on the right side of the equals sign, but as a whole does not represent an expression.
There are some other syntax problems you have. You can't modify a function paramter's value (num2-- isn't allowed).
The logic also doesn't make sense. return returns an expression immediately. To fix your code, you need to create a local variable from num2, and move the return statement to the end.
fun power(num1 : Int, num2: Int): Int {
var result = 1
var count = num2
while (count != 0) {
result *= num1
count--
}
return result
}
FYI, there's a function called repeat that is simpler than using a while loop with a counter. It runs the code inside the brackets by the number of times you give.
fun power(num1 : Int, num2: Int): Int {
var result = 1
repeat(num2) {
result *= num1
}
return result
}
You function contains multiple errors, I suggest you to study Kotlin, here a reference. Kotlin website has some more material.
Back to your problem, I have modified your function:
fun power(num1 : Int, num2: Int): Int {
var result = 1
var num2_local = num2
while (num2_local != 0) {
result *= num1
num2_local--
}
return result
}
Problems with your version:
you return from the function immediately
basic types args passed to kotlin functions are passed by const copy, this means that you cannot modify them (e.g num2--)
If you keep a local modifiable reference (var keyword) withing your function, then you achieve your goal
It would be a basic question, but I couldn't figure out a solution. I need to initialize a constant out of the right-side value of below either type.
val test: Either<String, Int> = 1.right()
I tried something like below but it shrinks the scope of the constant.
when(test) {
is Either.Right -> {val get:Int = test.b}
is Either.Left -> println(test.a)
}
I want that get to be scoped outside of when statement. Is there any way to do it or Arrow Either is not made for this purpose?
The important question is: what should happen if the Either is Left. In this example it is created close to where it's used, so it is obvious to you as a developer. But to the compiler what is inside the Either can be either an Int or a String.
You can extract the value using for example fold:
val x = test.fold({ 0 }, {it}) // provide 0 as default in case the Either was a `Left`
// x = 1
another option is getOrElse
val test = 1.right()
val x = test.getOrElse { 42 } // again, default in case it was a `Left`
// x = 42
You can also work with it without unwrapping it:
val test = 1.right()
val testPlus10 = test.map { it + 10 } // adds 10 to `test` if it is `Right`, does nothing otherwise
val x = testPlus10.getOrElse { 0 } // unwrap by providing a default value
// x = 11
For more example check the official docs.
Recommended reading: How do I get the value out of my Monad
I created a Delegate class in Kotlin, for 'cyclic' variables, such as hours:
when '25' is added to an hour with initial value '0', the result should be '1',
since there is no such thing as '25' hours.
The class I created works, but when I reassign such a delegated variable,
and then print it using 'print(...)',
I get an Error saying 'Smart cast is impossible, X is a mutable variable'
Am I doing something wrong ?
How could I fix the problem ?
I have tried to add an explicit cast, which helped,
but gives a Warning saying 'No cast needed', while it does not work without the cast.
this is the minimal code to reproduce the Error:
package <package name>
import kotlin.reflect.KProperty
fun main(){
val test = Test()
test.hour = 25
print(test.hour)
// this works: print(test.hour as Number) ("No cast needed")
}
// just a class which uses the delegate
class Test {
var hour by CyclicVariable(24)
}
// the delegate class
class CyclicVariable(val max: Number, var value: Number = 0){
operator fun getValue(reference: Any?, property: KProperty<*>): Number = value.toDouble()
operator fun setValue(reference: Any?, property: KProperty<*>, value: Number) {
val result = value.toDouble() % max.toDouble()
this.value = if (result >= 0) result else max.toDouble() + result
}
}
expected result: 1.0 on console
actual result:
Error:(12, 11) Kotlin: Smart cast to 'Int' is impossible, because 'test.hour' is a mutable property that could have been changed by this time
The problem occurs, because there is no method print with Number parameter.
You can just use test.hour.toString().
Kotlin tries to cast this variable to Int, as it sees, that you set an int to the variable: test.hour = 25. But it can't, because the variable is mutable.
Here's the problem in which I encountered this issue:
The function should compare the value at each index position and score a point if the value for that position is higher. No point if they are the same. Given a = [1, 1, 1] b = [1, 0, 0] output should be [2, 0]
fun compareArrays(a: Array<Int>, b: Array<Int>): Array<Int> {
var aRetVal:Int = 0
var bRetVal:Int = 0
for(i in 0..2){
when {
a[i] > b[i] -> aRetVal + 1 // This does not add 1 to the variable
b[i] > a[i] -> bRetVal++ // This does...
}
}
return arrayOf(aRetVal, bRetVal)
}
The IDE even says that aRetVal is unmodified and should be declared as a val
What others said is true, but in Kotlin there's more. ++ is just syntactic sugar and under the hood it will call inc() on that variable. The same applies to --, which causes dec() to be invoked (see documentation). In other words a++ is equivalent to a.inc() (for Int or other primitive types that gets optimised by the compiler and increment happens without any method call) followed by a reassignment of a to the incremented value.
As a bonus, consider the following code:
fun main() {
var i = 0
val x = when {
i < 5 -> i++
else -> -1
}
println(x) // prints 0
println(i) // prints 1
val y = when {
i < 5 -> ++i
else -> -1
}
println(y) // prints 2
println(i) // prints 2
}
The explanation for that comes from the documentation I linked above:
The compiler performs the following steps for resolution of an operator in the postfix form, e.g. a++:
Store the initial value of a to a temporary storage a0;
Assign the result of a.inc() to a;
Return a0 as a result of the expression.
...
For the prefix forms ++a and --a resolution works the same way, and the effect is:
Assign the result of a.inc() to a;
Return the new value of a as a result of the expression.
Because
variable++ is shortcut for variable = variable + 1 (i.e. with assignment)
and
variable + 1 is "shortcut" for variable + 1 (i.e. without assignment, and actually not a shortcut at all).
That is because what notation a++ does is actually a=a+1, not just a+1. As you can see, a+1 will return a value that is bigger by one than a, but not overwrite a itself.
Hope this helps. Cheers!
The equivalent to a++ is a = a + 1, you have to do a reassignment which the inc operator does as well.
This is not related to Kotlin but a thing you'll find in pretty much any other language
I'm trying to understand why let is needed. In the example below I have a class Test with a function giveMeFive:
public class Test() {
fun giveMeFive(): Int {
return 5
}
}
Given the following code:
var test: Test? = Test()
var x: Int? = test?.giveMeFive()
test = null
x = test?.giveMeFive()
x = test?.let {it.giveMeFive()}
x gets set to 5, then after test is set to null, calling either of the following statements return null for x. Given that calling a method on a null reference skips the call and sets x to null, why would I ever need to use let? Are some cases where just ?. won't work and let is required?
Further, if the function being called doesn't return anything, then ?. will skip the call and I don't need ?.let there either.
let()
fun <T, R> T.let(f: (T) -> R): R = f(this)
let() is a scoping function: use it whenever you want to define a variable for a specific scope of your code but not beyond. It’s extremely useful to keep your code nicely self-contained so that you don’t have variables “leaking out”: being accessible past the point where they should be.
DbConnection.getConnection().let { connection ->
}
// connection is no longer visible here
let() can also be used as an alternative to testing against null:
val map : Map<String, Config> = ...
val config = map[key]
// config is a "Config?"
config?.let {
// This whole block will not be executed if "config" is null.
// Additionally, "it" has now been cast to a "Config" (no
question mark)
}
You need to use let if you want to chain function calls that aren't defined on the type you are chaining from.
Let's say the definition of your function was this instead:
// Not defined inside the Test class
fun giveMeFive(t: Test) {
return 5
}
Now, if you have a nullable Test and want to call this function in a chain, you have to use let:
val x = test?.let { giveMeFive(it) }
The .let{} extension function in Kotlin:
Takes the object reference as the parameter on which .let{} is called.
Returns value of any non-primitive data-type which has been returned from with let{} function. By default, it returns undefined value of kotlin.Any class.
Declaration in package kotlin:
public inline fun <T, R> T.let(block: (T) -> R): R {
return block(this)
}
Simple practical demonstration to see how .let{} extension function works in Kotlin.
Sample Code 1:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
"Done" // Returnning some string
}
println("Print 2: $builder")
println("Print 3: $returnVal")
Sample Code 1 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: Done
In Sample Code 1:
We created the final object of type StringBuilder with initialization value "Hello ".
In builder.let{}, the builder object reference will be passed to arg.
Here, the output Print 2: Hello World and Print 3: Hello World means that the builder and arg, both are pointing to the same StringBuilder object-reference. That's why they both print the same String value.
In the last line of .let{} function block, we are returning "Done" String value which will be assigned to returnVal.
*Hence, we get Print 3: Done output from returnVal.
Sample Code 2:-
val builder = StringBuilder("Hello ")
println("Print 0: $builder")
val returnVal = builder.let { arg ->
arg.append("World")
println("Print 1: $arg")
arg.length
}
println("Print 2: $builder")
println("Print 3: $returnVal") // Now return val is int = length of string.
Sample Code 2 Output:-
Print 0: Hello
Print 1: Hello World
Print 2: Hello World
Print 3: 11
In Sample Code 2:
What's difference:
In the last line of .let{} function block, we are returning the Int value equals to the length of StringBuilder object arg whose value at this line of code is "Hello World". So length = 11 of type Int will be assigned to returnVal.
*Hence, we get Print 3: 11 as output from returnVal.
Also try these:-
.run() {}
.apply() {}
with(obj) {}
.also() {}
Happy Coding...
fun <T, R> T.let(f: (T) -> R): R = f(this)
.let block does not equal to in multiThreading
val x? = null
if(x == null) {
}
and
x?.let{
}
.let block is thread-safe