Syntatically, what’s wrong with just allowing us to do this?
when (c = a.b) { /*...*/ }
Instead of the current, more verbose:
when (val c = a.b) { /*...*/ }
Especially when we cannot declare var
anyway?
Syntatically, what’s wrong with just allowing us to do this?
when (c = a.b) { /*...*/ }
Instead of the current, more verbose:
when (val c = a.b) { /*...*/ }
Especially when we cannot declare var
anyway?
For one thing, the syntax is very close to when (c == a.b) { /*...*/ }
— also syntactically valid, but with a very different meaning. If that’s what you intended, it would be very easy to mistakenly omit one of the two =
symbols, which would completely change the meaning of c
inside the block without generating any error.
Mistakenly using =
instead of ==
is a significant problem in languages like C (where some coding standards recommend the awkward and ugly practice of always putting constants first in comparisons, to turn the mistake into a compile error). So allowing a single-character typo to be so dangerous would be bad for Kotlin.
Also, defining a new (constant) variable in this way is uncommon IME, and you might find the extra four characters a useful way to make it stand out.
I think this wouldn’t be an issue, right? Only if you already have a c
variable in scope, and also if it’s a type that could be compared to a.b
. Since I would assume that 99% of the time when you’re doing this, you don’t already have a variable called c
declared, then if you accidentally did when (c == a.b)
, you’d get a compiler error, because the compiler wouldn’t know what c
is; it hasn’t been declared.
Usually, it is the opposite. People would like to do ==
, but they accidentally do =
.
Anyway, for me this is just for code clarity. Kotlin doesn’t try to provide the shortest possible syntax, but the most readable. It is concise, but expressive. In many cases it requires some additional code, just to make the intention more clear. For example fun
, which is not required in Java. Please note val
could be entirely removed from the language, but authors probably decided that creating a new variable should be explicit.
As broot and I said, the common error is the opposite: intending ==
but mistakenly typing =
. And for the ==
to have been syntactically correct, c
must be in scope, and must be of a compatible type.
If c
is a val
or param, then omitting one of the =
would give a compiler error (another demonstration of why you should use val
where possible!) — but if c
is a var
, then it’d give code that compiles fine and yet means something very different. That’s a dangerous possibility for a common, single-character typo!
Another reason for requiring the val
is consistency: other places that define a new variable require it (or var
), so requiring it here is logical and avoids a special case.
if
c
is avar
, then it’d give code that compiles fine
Is this true? I would imagine it still wouldn’t compile because assignments are not expressions and cannot be used where expressions are required.
klitos: Under the proposed new syntax, the =
wouldn’t be an assignment; it’d be a declaration with an initialiser.
But yes, some of my previous comment was wrong… Now I look more thoroughly, it’s even worse than I thought!
The existing when (val c = …)
syntax is perfectly valid if c
already exists; the new variable shadows the old one, just as it would for any other val
declaration in an inner scope. And the same would have to apply to the proposed syntax in this page, too.
So if when (c == …)
were valid, then under the proposed new syntax when (c = …)
would always be valid too! It would declare a new variable c
, initialised to the RHS and inferring its type, shadowing any existing c
(of any type or mutability).
As mentioned above, if when (c == …)
were valid, there would have to be an existing c
with a type compatible with the RHS — and hence compatible with the new c
as well. And so most uses of c
within the when
block would be valid, and the typo would cause a compile error only in the (relatively uncommon) case that:
c
was a var
; andc
was reassigned within the when
block.In all other cases, mistyping =
instead of ==
(a fairly common typo, and not obvious) would give code that compiled fine, but behaved differently. I hope it’s clear why this sort of gotcha would be undesirable for a language.
Yes, taking the current design of Kotlin, I would definitely expect when (c = ...)
to create a new block-scoped variable, shadowing any potential variables from the outer scope.
However, this case is still highly hypothetical for much different reason. Why would anyone use when
with booleans? This makes it effectively an if
. But still this is not an excuse for adding a feature which just doesn’t fit the Kotlin design very well.
The question has been opened here
and discussed here