Kotlin introduces itself as supporting functional ...
# announcements
h
Kotlin introduces itself as supporting functional programming but it inherited the poor typing system of Java! For instance if you try to do
Pair(a,b) as? Pair<String, Boolean>
where
a
or
b
can be null, there is a Java warning that says
Unchecked cast: Pair<String?, Boolean?> to Pair<String, Boolean>
. By supporting more strong typing system which supports generics type checking, we can make sure we're developing less buggy programs. I want to know is it possible to do so? For instance, why we cannot hold type info in the KClass in the runtime to check these kind of stuff? Thank you.
g
Types are non-reified in Java and Kotlin, and it’s not bad itself 0What is your actual case? Because your example is not clear for me, Kotlin has nullability on level of type system, why do you need cast to check it in pair? If you want to check that pair content is not null, why not just write simple extension function for this, something like:
Copy code
fun <A : Any, B : Any> Pair<A?, B?>.takeIfNonNull(): Pair<A, B>? {
    val first = first ?: return null
    val second = second ?: return null
    return Pair(first, second) 
    // Also can be optimized with unsave cast: 
    // @Suppress("UNREACHABLE_CODE")
    // return this as Pair<A, B>
}
reified vs non-reified generics is quite big topic with multiple arguments on each side And on JVM this choice already done, introduction of full-blown reified generics would be a huge problem for Java interop But many use cases of refiied generics are covered in Kotlin by other features (such as smart cast), so I think that you should provide your use cases, maybe they can be solved using some other way
h
Thank you @gildor I agree I can check that by defining some methods in my code but I want the compiler and idea to do that for me, and I focus to think about defining correct types. The use-case is as simple as checking types in
as?
operator. Search in your code base and give me some of your use-cases, then I would make those types generic and that would be my use-case.
So I'm in reifid side i guess 😄
g
Kotlin supports reified generics for inline functions, which covers many real-life cases
Not with cast, but cast doesn't look for me as the best solution in many cases
h
I agree
what about
is
? give me your use-cases so I can make them generic.
s
Well, what are you really trying to do here? Are you attempting to pattern-match based on contained type? are you serializing data from another source? we can definitely have safe, correct programs without reified generics, but the best solution often depends on the problem
h
My original use-case was
Copy code
val a:String? = ...
val b:Boolean? = ...
(Pair(a, b) as? Pair<String, Boolean>)?.let{(aa,bb) -> 
    doSomething(aa, bb)
}
which could be a solution for https://discuss.kotlinlang.org/t/kotlin-null-check-for-multiple-nullable-vars/1946/55 discussion. But I can think about many more use-cases.
s
That’s a very convoluted way to write
if (a != null && b !=null)
👆 4
g
convoluted and also less efficient, it allocates an object
h
I know! both of them! But it's shorter and safer! There's a trade off that a developer can accept, but the language doesn't support.
Also I mentioned above that I can check that with a code, in fact everything that Java and Kotlin can do someone can code in bytecode, but I'm using Kotlin to provide some checks and generate some stuff for me, so I can focus to real problem.
g
But it’s shorter and safer
It’s not safer, because you repeat type declaration, so it’s a lot easier to introduce bug: This works
Copy code
val a:String? = ...
val b:Boolean? = ...
(Pair(a, b) as? Pair<String, Boolean>)?.let{(aa,bb) -> 
    doSomething(aa, bb)
}
This doesn’t work, it’s completely broken because of very subtle bug
Copy code
val a:String? = ...
val b:Boolean? = ...
(Pair(b, a) as? Pair<String, Boolean>)?.let{(aa,bb) -> 
    doSomething(aa, bb)
}
Also it’s not shorter:
Copy code
val a:String? = ...
val b:Boolean? = ...
if (a != null && b != null) {
    doSomething(a, b)
}
49 characters for check and call instead of 76 in your example Also because Kotlin does smart cast in this case, it would be checked on compile time for nullability. If doSomething requires non-null arguments, it’s impossible for example to do such mistake and get NPE as in Java
Copy code
if (a != null || b != null) {
    doSomething(a, b)
}
You see,
||
instead of
&&
, Smart cast will not work, compilation will fail, in java and other languages without nullability support in type system it will fail on runtime
fact everything that Java and Kotlin can do someone can code in bytecode
It’s not true, because a lot of language features of Java and (even more) Kotlin are done on compile time, so a lot of information is not available on runtime, only compile time, such as big part of type system, not only generics
h
Thank you @gildor for your time!
49 characters for check and call instead of 76 in your example
You need to repeat those 49 characters all around when you pass
Pair(a, b)
around methods to use
a
and
b
but you need 30 of them in those method to check and use
a
and
b
again and again!
This doesn’t work, it’s completely broken
Good to see you're seeing its advantage and safety 🙂
it’s impossible for example to do such mistake and get NPE as in Java
I'm trying to think about Kotlin as an independent language of Java because it's support multiplatform, but you keep mentioning Java, and it's not your fault! Maybe some decisions about Kotlin was contradictory! For instance, they decided to go for multiplatform and be independent but they keep being dependent to JVM environment! It's confusing!
so a lot of information is not available on runtime, only compile time, such as big part of type system
you mentioned my exact point of view here! "type system"! so stronger type system is what these languages do on above of bytecode. I need it to be more stronger, that's just it. Thank you for helping me clearing my mind.
g
It's not confusing, JVM is the first, and by far the most popular platform for Kotlin
👍 1
Good to see you're seeing its advantage and safety 🙂
No, I don't see, if this syntax would work on runtime, it will be still broken, see, there is a bug and usage of cast in this case is error prone, check my example carefully
h
I see your point! you just changed the place of
a
and
b
isn't it? So the
doSomething
would not get called or if this pair had came from arguments of the method it would not get compiled. Is that what you've wanted to mention? Because I think this is what we're looking at by typing system.
g
Yes, and standard way to use Kotlin type system works perfectly for this particular example, much better (shorter and safer), than type check using cast which you would like to use I don't say that there are no valid cases for runtime check of generic types, I just want to say that many of those cases can be solved without this, like your example showed perfectly, that it's not the best solution for your sample code This is why I asked about your use case, what kind code is requires this, not in general, for sure there are cases, but particularly to just see how often such code is used and solution without reified generics are not working
👍 1