I just noticed a behavior change in Kotlin 1.4 (af...
# announcements
n
I just noticed a behavior change in Kotlin 1.4 (after finally upgrading a project from 1.3):
mapOf("a" to 1L, "b" to 2)
now has a type
Map<String, Long>
while it had type
Map<String, Any>
in 1.3. This caused a runtime error because the
2
was passed to some Java code which then casts it to an
int
. It was easy enough to fix by using `mapOf<String, Any>("a" to 1L, "b" to 2)`but it makes me wonder: could I somehow prevent the automatic promotion of the
2
to a
2L
?
s
I’m not sure what you mean, that is how you prevent automatic promotion. You could also set the correct return type or annotate the variable if either is applicable.
Are you asking if there’s like a compiler flag or something to set?
n
No.
val b = 2; val m = mapOf<"a" to 1L, "b" to b); val i = m["b"] as Int
works, but
val m = mapOf<"a" to 1L, "b" to 2); val i = m["b"] as Int
says "java.lang.Long cannot be cast to java.lang.Integer". My understanding is that this happens because
2
is a valid literal for a
Long
value. I would like to prevent that "promotion" to
Long
. Something like
2I
which would make sure the type is
Int
and not
Long
.
Just found out that `mapOf("a" to 1L, "b" to 2 as Int)["b"] as Int`works while
mapOf("a" to 1L, "b" to 2)["b"] as Int
fails. Thus
2 as Int
will prevent automatic promotion to
Long
. I still would think that not accepting
2
as a value for a
Long
would be better
r
imho, the situation "I want to have both Long & Ints in this structure" is so very uncommon, that having to manually cast the literal to Int will even help you in readability of that
n
I really do not see why the differentiation between Int and Long is any different then e.g. between Int and String.Kotlin (IMHO correctly) refuses to widen an Int variable value into a Long, so why does it do that for literals. And the language even says: "any number literal less than Int.MAX_VALUE is an Int unless you add a L" (or e.g. a U these days). Thus, I see this implicit promotion to Long as a bug. BTW:
mapOf("a" to 1L, "b" to 2, "c" to true)["b"] as Int
works as well (i.e.
2
stays an
Int
and is not promoted to
Long
).
t
I actually agree that this Int literal shouldn't be automatically interpreted as a Long value. However, I doubt even more that an untyped map like that is a good way to pass around values of different types.
n
Now that I completely agree with! My very first review comment when I saw the code was to replace the map with a poko.