0

When creating a variable through function constructors fun funname() (Is that what they're called?) It seems that they are declared as vals. Since vals cannot be reassigned (which I need to do for reasons), I was wondering if there was a way to declare a variable as var in a line of code before the function, and then assign a value through the function.

Please keep in mind that I just started learning Kotlin yesterday. I am open to all alternatives.

public fun singlebattle(enemyhealth : Int, enemyattack : Int , enemyname : String)

When I try to reassign enemy health, I get the error "Cannot reassign val", So I'm trying to declare the enemyhealth and others as vars.

The error appears here: enemyhealth = enemyhealth - playerstats[1]

When I subtract enemyhealth by player damage to show the player attacked

I am using Repl.it Kotlin version 1.3.72

4
  • At the top of your function, create a var: var mutableEnemyHealth = enemyhealth and then later modify that instead: mutableEnemyHealth = ... Commented Sep 30, 2020 at 16:00
  • Can you give me an example? I did what I think you meant, and I got the following errors: property must be initialized or be abstract public var mutableEnemyhealth : Int And a type annotation is required on a value parameter public fun singlebattle(enemyhealth = mutableEnemyhealth , enemyattack : Int , enemyname : String){ Commented Sep 30, 2020 at 16:07
  • Does this answer explain? Commented Sep 30, 2020 at 16:12
  • Ah, yes. The answer is clear now, thank you both so much, and my apologies for the late reply. It seems I need to think outside the box a little more Commented Sep 30, 2020 at 16:17

1 Answer 1

1

Ooookay this ended up pretty long but I hope it helps at least!

That's not a constructor, because it's not constructing an object - it's just a function definition, and when you call that function, with singleBattle(), you need to pass in the listed parameters by putting them in the parentheses.

Firstly yeah, those parameters passed into the function become local vals inside the function block - they're read-only. You can do stuff with them, and assign the results to another val or var that you declare inside the function.

But I'm assuming what you're actually trying to do is something like this:

  • A has access to variables like finalBossHealth
  • A passes finalBossHealth into function B (as enemyhealth)
  • B changes the value of enemyHealth
  • A sees that change in finalBossHealth because it's "the same variable"

which you can't do, because your parameters are fixed vals. You basically have two options:


Define your variables outside the function, where A and B can both see them

So long as the function is in the same class as the variables (fields), it will be in the same scope and it'll be able to change them directly. In this case there's no real point in passing that value in, since it can read and write them directly

var enemyHealth = 9999

public fun singleBattle() {
    enemyHealth = enemyHealth - 100
}

in practice you'd probably have a list of enemies or something, and you'd pass in an index so the function can look one up and modify it.


Return an updated value for A to use

This is the functional approach - you pass in certain data, the function does something with it, and passes a result out. Ideally if you pass the same data in, you get exactly the same result back each time - so it only relies on the parameters, not any state outside of the function (like fields in the class). If it doesn't have any side effects outside of the class (like changing a var in the class) then it's called a pure function.

These are easy to reason about, because they just do one thing - put values in, get specific result, easy!

public fun singlebattle(enemyhealth : Int, enemyattack : Int , enemyname : String): Int {
    // calculate whatever
    return updatedHealth;
}

this one just returns an Int, so the caller would call singleBattle and then do something with the result. singleBattle doesn't need to know anything about the external state, it just takes some values and does something useful with them.

If you need to return more than just one value (say the attack can decrease) you can create some kind of data structure that holds a bunch of values:

data class Fighter(val health: Int, val attack: Int, val name: String)

public fun singlebattle(player: Fighter, enemy: Fighter): Fighter {
    // calculate the player's state after the fight
    return player.copy(health = newHealth)
    // or just return Fighter(newHealth, player.attack, player.name)...
}

if you want to return more than one Fighter (so you have the updated enemy state too) you might want to use another object that includes them both, like data class Battle(val fighter1: Fighter, fighter2: Fighter)


You can combine these (and lose the benefits of a pure function, but it might be easier to do things this way) by taking advantage of the fact you're passing references into a function:

// I'm using vars here because we're gonna change them
data class Fighter(var health: Int, var attack: Int)

val player = Fighter(100, 999)
val monster1 = Fighter(9999, 5)

singleBattle(player, monster1)

fun singleBattle(fighter1: Fighter, fighter2: Fighter) {
    // do the fight, update the values
    fighter1.health = fighter1.health - fighter2.attack
    // etc... you can also say fighter1 -= fighter2.attack as a shorthand
}

this function doesn't return anything, because it's just changing the variables in those Fighter objects that were passed in. The call passed in references to the player and monster1 objects, not new copies, and although you can't change the value of fighter1 (i.e. which Fighter object it refers to), you can poke around inside that object. And everything that can see that same object (has a reference to it) will see the updates. So after calling singleBattle(player, monster1) you'll see the new values for player1.health etc, because player1 points to the same Fighter object in memory that fighter1 does while the function is messing with it.

Sign up to request clarification or add additional context in comments.

3 Comments

you tried hard for this. definitely deserve an upvote :D
Many thanks, my friend. I apologize for the late, Late reply, as I was at school. I think your answer really helped me understand the kotlin language as a whole, variable handling, and what I need to do to get the results I want. I will be referring back to this answer for weeks, perhaps months to come. Your labor was not in vain.
@Mike yeah it's touching on a lot of different concepts - if you read up on scope, local and global variables, pure functions and side-effects, and the difference between objects and primitives, hopefully you'll have a good overview! Scope is especially important with Kotlin, so you can understand what the heck is going on with these things: kotlinlang.org/docs/reference/scope-functions.html And cheers @mohsen!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.