4

Coming from Java, I was surprised to find out that Kotlin doesn't allow assignments as expressions.

Is there a reason for that?

Java (Works)

    @Test
    public void test_x() {
        List<String> elements = null;
        for (final String x : (elements = List.<String>of("1", "2"))) {
            System.out.println(x);
        }
    }

Kotlin (Compile-time error)

    /*Assignments are not expressions, and only expressions are allowed in this context*/
    @Test
    fun test_x() {
        var elements: List<String> = listOf()
        for (x in (elements = listOf("1", "2"))) {
            println(x)
        }
    }
sero
  • 149
  • 1
  • 3

2 Answers2

8

The only people who can answer this question are the designers of Kotlin. However, we can make some educated guesses:

  • Assignment is a fundamentally imperative operation. In pure functional programming, there are no assignments, in fact, the very idea of "assignment" doesn't even make sense in FP. Assignment is about changing the state of the world: before the assignment, variable foo was bound to value bar, after the assignment, it is bound to value baz. Operations that change the state of the world (e.g. printing, reading from the console), generally have a Unit or void type and/or are statements. (Depending on which one of those your programming language actually has.)
  • Accidentally assigning when you mean to test for equality, is a really common mistake. (Just within the last couple of hours, I saw at least three different questions on Stack Overflow that were caused by that mistake.) If assignments are statements, that mistake simply cannot happen.
  • Kotlin was influenced by Scala, even if in a lot of cases in how not to do things. In Scala, like several newer languages, assignments are "statements". (Technically, Scala doesn't have statements, everything is an expression, but assignments evaluate to () which is the singleton inhabitant of the Unit type which denotes a useless return value.)
Jörg W Mittag
  • 101,921
  • 24
  • 218
  • 318
6

Kotlin allows named arguments, which also uses the = as separator. A function fun foo(bar: Int) might be called as foo(42) or foo(bar = 42). Thus, assignment cannot occur within expressions without introducing substantial ambiguity. (Other languages can avoid this by using a different syntax for named arguments, by having a separate inline assignment operator, or by requiring inline assignments to be parenthesized, e.g. var x = 0; foo(bar = (x = 42)).)

There's also a line of thinking in functional-inspired languages that assignments are side effects and should therefore be discouraged and made more explicit. Ideally, variables are assigned exactly once, during initialization (as with Kotlin's val).

Assignments in expressions are mostly useful in control flow constructs, e.g something like while (it = next()) .... Maybe Kotlin will get suitable syntax in the future.

amon
  • 132,749
  • 27
  • 279
  • 375