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

Abhishek kumar
  • 4,347
  • 8
  • 29
  • 44
Mike
  • 1
  • 1
  • At the top of your function, create a var: `var mutableEnemyHealth = enemyhealth` and then later modify _that_ instead: `mutableEnemyHealth = ...` – Ben P. Sep 30 '20 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){`` – Mike Sep 30 '20 at 16:07
  • Does [this answer](https://stackoverflow.com/a/42540294/10134209) explain? – gidds Sep 30 '20 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 – Mike Sep 30 '20 at 16:17

1 Answers1

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.

cactustictacs
  • 17,935
  • 2
  • 14
  • 25
  • you tried hard for this. definitely deserve an upvote :D – Mohsen Sep 30 '20 at 20:26
  • 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 Sep 30 '20 at 22:42
  • @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: https://kotlinlang.org/docs/reference/scope-functions.html And cheers @mohsen! – cactustictacs Oct 01 '20 at 11:53