I am getting the val cannot be reassigned compile time error. But I have declared the variable as `var` only - kotlin

val cannot be reassigned compile time error var variable. Can't we change the array value?
Error
Array.kt:11:3: error: val cannot be reassigned
Code:
import java.util.Scanner
fun main(args: Array< String>){
println("Enter the no")
val scanner = Scanner(System.`in`)
var nos = Array<Int>(5){0}
var i : Int = 1
for (i in 1..3){
nos[i] = scanner.nextInt()
i = i+1
}
println("Given values $nos")
}

The for (i in 1..3) ... statement redefines i for the scope of its body, where it becomes a val (it's actually a separate variable that shadows the i declared outside the loop).
You can fix the code by using different names for these variables, or, in your case, by simply removing var i: Int = 1 and i = i + 1:
val scanner = Scanner(System.`in`)
var nos = Array<Int>(5) { 0 }
for (i in 1..3) {
nos[i] = scanner.nextInt()
}
println("Given values $nos")
UPD (answering to the comment): You can iterate in the opposite direction or using a non-unit step by building a progression with functions downTo and step, both described here in the reference.

var i : Int = 1
for (i in 1..3){
nos[i] = scanner.nextInt()
i = i+1
}
In this code you declared not one, but two variables with the name i because the for header creates its own declaration. Within the loop, only the version declared in the for header is visible, and that one is a val by definition.
Having said that, I'm unclear on what you were trying to achieve since everything looks like it would work just the way you want it without trying to update i in the loop.

Related

Expecting member declaration (this happens when using a variable from another class)

The code here works:
fun main(){
val pizza = random()
print(pizza.num)
}
class random{
val num = 5
}
But the code here does not work
fun main(){
val pizza = random()
print(pizza.num)
}
class random{
val num = 5
num = 7
}
The only difference is that in the last line of code I reassign the variable num. The only thing I did was change this variable from 5 to 7.
Why is this causing errors?
Note This is the online IDE I was using: https://developer.android.com/training/kotlinplayground
2 things:
Firstly, you can't reassign vals. you need to change that to var
Secondly, you can't do assignments directly in a class body, only declarations.
However, you could put it in an init block like this to get the desired result:
class random{
var num = 5
init {
num = 7
}
}
you might want to read the documentation about kotlin classes here

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

Extract value out of Kotlin arrow Either type and assign it to const

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

Traveling salesman with random initial solution, optimization algorithm returning unexpected result

I know traveling salesman is well known, but I need some help on why my optimization algorithm is returning an unexpected result. I have created an initial solution by selecting cities in a random order. I have also created a class with a constructor with the distance matrix and initial solution as parameters. The optimization algorithm is very simple; it swaps two cities and checks if the route distance has been improved, and if it has improved the best solution should be updated. This goes on for 6 iterations. The problem is that the it seems like the best solution is updated and overwritten even if the condition for overwriting it is not met. I will add an image showing the results from a test run.
It seems like the variable bestSolution is overwritten but not bestDistance. I must have some sort of tunnel vision, because I can't figure this one out even if the code is really simple. Can someone please chime in why bestSolution is overwritten and returned with unexpected result?
Code example below:
package RandomMethod
import GreedyHeuristic
import java.util.*
fun main(args: Array<String>) {
/*A B C*/
val distances = arrayOf(/*A*/ intArrayOf(0, 2, 7),
/*B*/ intArrayOf(2, 0, 9),
/*C*/ intArrayOf(7, 9, 0))
val initalSolution = findRandomRoute(distances)
println("Initial solution: $initalSolution")
println("Total distance: ${findTotalDistance(distances, initalSolution)}\n")
val optimizedSolution = GreedyHeuristic(distances, initalSolution).optimize()
println("\nOptimized solution with Greedy Heuristic: $optimizedSolution")
println("Total distance: ${findTotalDistance(distances, optimizedSolution)}")
}
fun areAllCitiesVisited(isCityVisited: Array<Boolean>): Boolean {
for (visited in isCityVisited) {
if (!visited) return false
}
return true
}
fun findTotalDistance(distances: Array<IntArray>, orderToBeVisited: MutableList<Int>): Int {
var totalDistance = 0
for (i in 0..orderToBeVisited.size - 2) {
val fromCityIndex = orderToBeVisited.get(i)
val toCityIndex = orderToBeVisited.get(i + 1)
totalDistance += distances[fromCityIndex].get(toCityIndex)
}
return totalDistance
}
fun findRandomRoute(distances: Array<IntArray>): MutableList<Int> {
val visitedCities: Array<Boolean> = Array(distances.size, {i -> false})
// Find starting city index. 0 = A, 1 = B, 2 = C .... N = X
var currentCity = Random().nextInt(distances.size)
val orderToBeVisited: MutableList<Int> = mutableListOf(currentCity)
visitedCities[currentCity] = true
while (!areAllCitiesVisited(visitedCities)) {
currentCity = Random().nextInt(distances.size)
if (!visitedCities[currentCity]) {
orderToBeVisited.add(currentCity)
visitedCities[currentCity] = true
}
}
return orderToBeVisited
}
And the class for optimization:
import java.util.*
class GreedyHeuristic(distances: Array<IntArray>, initialSoltion: MutableList<Int>) {
val mInitialSolution: MutableList<Int> = initialSoltion
val mDistances: Array<IntArray> = distances
fun optimize(): MutableList<Int> {
var bestSolution = mInitialSolution
var newSolution = mInitialSolution
var bestDistance = findTotalDistance(mDistances, bestSolution)
var i = 0
while (i <= 5) {
println("best distance at start of loop: $bestDistance")
var cityIndex1 = Integer.MAX_VALUE
var cityIndex2 = Integer.MAX_VALUE
while (cityIndex1 == cityIndex2) {
cityIndex1 = Random().nextInt(mInitialSolution.size)
cityIndex2 = Random().nextInt(mInitialSolution.size)
}
val temp = newSolution.get(cityIndex1)
newSolution.set(cityIndex1, newSolution.get(cityIndex2))
newSolution.set(cityIndex2, temp)
val newDistance: Int = findTotalDistance(mDistances, newSolution)
println("new distance: $newDistance\n")
if (newDistance < bestDistance) {
println("New values gived to solution and distance")
bestSolution = newSolution
bestDistance = newDistance
}
i++
}
println("The distance of the best solution ${findTotalDistance(mDistances, bestSolution)}")
return bestSolution
}
fun findTotalDistance(distances: Array<IntArray>, orderToBeVisited: MutableList<Int>): Int {
var totalDistance = 0
for (i in 0..orderToBeVisited.size - 2) {
val fromCityIndex = orderToBeVisited.get(i)
val toCityIndex = orderToBeVisited.get(i + 1)
totalDistance += distances[fromCityIndex].get(toCityIndex)
}
return totalDistance
}
}
Kotlin (and JVM languages in general) doesn't copy values unless you specifically ask it to. This means that, when you do this:
var bestSolution = mInitialSolution
var newSolution = mInitialSolution
You're not setting bestSolution and newSolution to separate copies of mInitialSolution, but rather making them point at same MutableList, so mutating one mutates the other. Which is to say: your problem isn't that bestSolution is getting overwritten, it's that you're accidentally modifying it every time you modify newSolution.
You then reuse newSolution for every iteration of your while loop without ever creating a new list. This leads us to two things:
Because newSolution still aliases bestSolution, modifying the former also modifies the latter.
bestSolution = newSolution doesn't do anything.
As mentioned in a comment, the easiest way to fix this is by making strategic use of .toMutableList(), which will force copying the list.You can achieve this by making this change at the top:
var bestSolution = mInitialSolution.toMutableList()
var newSolution = mInitialSolution.toMutableList()
Then inside the loop:
bestSolution = newSolution.toMutableList()
Incidentally: As a general rule, you should probably return and accept List rather than MutableList unless you specifically want it to be part of the contract of your function that you're going to mutate things in-place. In this particular case, It would've forced you to either do something icky (like unsafe-casting mInitialSolution to MutableList, which should sound all sorts of warning bells in your head), or copy the list (which would've nudged you towards the right answer)

Override getValue and setValue to capselate a Pair

Let's say I have following class:
class Person() {
var age: Pair<String, Int> = Pair("person_age", 23)
// override getValue and setValue here
}
Now I want to capsulate the actual Pair and only want the user to read/write the second value of the pair. Is it possible to override the getValue and setValue methods so I can do something like this:
val p = Person()
p.age = 25
if(p.age <= 30)
Of course I can write own getter and setter methods for each property but one nice thing about Kotlin is that you have to write such less boilerplate code which will get lost then.
The following should probably already suffice:
class Person() {
var age : Int = 23 // public by default
private /* or internal */ fun toAgePair() = "person_age" to age // narrow visibility
}
So all your code accesses the age as you have shown:
val p = Person()
p.age = 25
if (p.age <= 30) ...
But if you require your Pair you just do the following instead:
p.toAgePair() // or skip that method and use: '"person_age" to p.age' instead
Alternatives to access the Pair content are: Pair.first, Pair.second or destructured, e.g.:
val myPair = Pair("person_age", 23)
// myPair.second = 25 // setting will not work however
myPair.let { (name, age) -> /* do something with it */ }
Or alternatively:
val p = Person()
val (name, age) = p.toAgePair()
// age = 25 // setting will not work however (and it wouldn't set the actual value inside the Pair if it would contain vars)
if (age < 30) // accessing is OK
However then you get access to both values which you probably didn't want in the first place, if I understood you correctly.
You could overcome the setting part using your own data class with a var but then again, you do not really gain something from it.
I wouldn't recommend you to use Pair at all. Maybe you could modify it (inherit from it, use extension functions) to suit your needs, but why try to change something as simple as Pair?. It is much easier and in this case also cleaner to just create your own class which suits your needs:
data class MyPair<out A, B>(
val first: A,
var second: B
)
val pair = MyPair("age", 1)
pair.second = 2
pair.first = 1 // error
This class has all important features which Pair has: generic types for first and second, and you can use destructuring declarations.
Now I want to capselate the actual Pair and only want the user to read/write the second value of the pair.
Assuming this means you want the first value to be final, but not the second one, there are some options.
If you only want one of the values to be writeable and readable, don't use a pair. It's not designed to be used like that. All the items of a Pair are vals.
If you want a Pair either way, can do this:
class Person(var age: Int = 23){
val pair: Pair<String, Int>
get() = Pair("person_age", age)
//Alternatively, if you don't want to use a property:
//fun getPair() = "person_age" to age
}
What this does is creating a final pair where the first value can't be modified, but the second can.
So now:
fun example(){
val person = Person()
person.age = 25;//Fine: Age is an int, and a var
//person.pair = Pair("something", 45)//fails: "Val cannot be reassigned
val pair = person.pair // Allowed. Accessing the pair still works
assert(pair.second == person.age) // This is true
}
However, if you're fine with a non-Pair solution, this works too:
data class Person (var age: Int, val string: String = "person_age")
fun example(){
val person = Person(23)
val (name, string) = person// Allowed! Just like with Pairs
person.age = 25; // Also allowed
//person.string = "something"//Not allowed
}
The n-touple unpacking is supported for data classes. If you don't have a data class, you need to declare an operator fun for each component you want to unpack. Example:
class Person (val string: String = "person_age", var age: Int){
operator fun component1() = string
operator fun component2() = age
}
But tbh, it sounds like the data class solution is the one you're looking for. It would lock the String to what it's initialized with, and because of the default value and its position, you can initialize it with a single positioned argument*
You could also use generics if you want to use the same class for multiple types.
* Assumes the code is in Kotlin. Positioned and default arguments don't work from Java code.
Here's how to overwrite a getter method in Kotlin
class Person {
var age: Int = 0
get() = if (field < 0) 0 else field
}
The attribute is accessed directly
fun main(args: Array<String>) {
val p = Person()
p.age = -28
println(p.age) //0
}