Question about destructing declarations


#1
    val (essenceId, essenceCount) = EssencePair(PURE_ESSENCE, plr.inventory.getAmount(PURE_ESSENCE))

Why does this work, but this doesnt:

    val (essenceId, essenceCount) = {
    EssencePair(PURE_ESSENCE, plr.inventory.getAmount(PURE_ESSENCE))
}

(The difference in brackets)

The reason I need brackets is because I want to do more complex computations within brackets, rather than just setting it equal to one thing every time.

This is an example of the complex computations I want to do within the brackets, that I wrote with scala code:

val (essenceId, essenceCount) = {
def lookup(id: Int) = inventory.computeAmountForId(id)

if (rune.level > 20) {
  (PURE_ESSENCE, lookup(PURE_ESSENCE))
} else {
  val count = lookup(RUNE_ESSENCE)
  if (count > 0) (RUNE_ESSENCE, count) else (PURE_ESSENCE, lookup(PURE_ESSENCE))
}

}

Thank you.


#2

It doesn’t work because, when you place braces around the RHS, it becomes a lambda expression.

However, if you invoke the lambda, then it should work as the EssencePair is its return value:

val (essenceId, essenceCount) = {
    EssencePair(PURE_ESSENCE, plr.inventory.getAmount(PURE_ESSENCE))
}()  // invoke by placing a pair of parentheses after it

#3

It works, but makes little to no sense to me and seems like a cheap hax. Can you explain more?


#4

Well { EssencePair(PURE_ESSENCE, plr.inventory.getAmount(PURE_ESSENCE)) } is a function literal of type () -> EssencePair. In other words, it takes no parameters and returns an EssencePair object.

Now a function literal doesn’t have component1() and component2() functions like a Pair object does and so when you try to destructure you get a compilation error. However, if you invoke the function (by adding empty parentheses) then it returns the EssencePair object because this is the last expression in the function and so destructuring now works.

I don’t know Scala very well but this may be what your Scala code is actually doing - the difference being that you don’t need parentheses to invoke a function which takes no arguments in that language but you do in Kotlin.

It’s certainly not a hack, it’s just the way stuff works.


#5

If you need to invoke lambda immediately, you can use run function from the standard library:

val (essenceId, essenceCount) = run {  
  if (rune.level > 20) {
    EssencePair(PURE_ESSENCE, lookup(PURE_ESSENCE))
  } else {
    val count = lookup(RUNE_ESSENCE)
    if (count > 0) EssencePair(RUNE_ESSENCE, count) else EssencePair(PURE_ESSENCE, lookup(PURE_ESSENCE))
  }
}

This is an idiomatic way to run block with multiple statements and return its result.