Why isn’t this legal? ``` class Foo<Bar>( ...
# announcements
b
Why isn’t this legal?
Copy code
class Foo<Bar>(
        initial: Bar?
) {
    
    private val internal: Any? = initial
    
    fun baz(): Bar? {
        val i = internal
        return if (i is Bar) i
        else null
    }
}
Error: Cannot check for instance of erased type: Bar
d
The actual type of
Bar
is not retained at runtime.
Foo<Int>
and
Foo<String>
are the same class at runtime. So you cannot know what the actual type of
Bar
is.
b
… I see
But won’t it throw a ClassCastException if I use
as!! Bar
and it’s not a
Bar
?
d
First of all there is no
as!!
. And no. It can't. It will create a warning ("Unchecked cast"). What you then have is called heap pollution. You will get the class cast exception at some point down the line when someone actually tries to use the object as it's true type.
1
b
Oh I think I was confusing Swift again XD They have an
as
,
as?
and
as!
So is this a JVM problem? Because I know that Kotlin/JS has been very responsible about encoding types into objects
d
Kotlin/JS also erases generics, afaik.
I'll give you an example:
Copy code
val listOfStrings = mutableListOf<String>("Hello")
doEvilStuff(listOfStrings, 1)
println(listOfStrings[1]) // will crash, Int is not a String

fun <T> doEvilStuff(list: MutableList<T>, number: Int) {
    list += number as T // will not crash, because this method does not know what `T` is!
}
b
Bluh. It totally should. If I were designing it, that would compile into a method that takes another argument which is the declared generic class type, and throw an exception immediately if that type is not correct.
d
You can opt-in to that by using
reified
keyword with
inline
function.
b
oh!
d
Also, this is why there is the "unchecked" warning 😉
b
But nothing like that is available for classes?
d
No. You'd have to pass in the class manually for example as
Class<Bar>
or
KClass<Bar>
b
Fun…

https://i.imgur.com/8ZiJwla.png

d
You can't have a
KClass
of a nullable type.
b
But it’s not…?
d
Does
Value
have any upper bound?
Because if it doesn't, then it's implicit upper bound is
Any?
, which is definitely nullable.
b
Back to my SSCCE:
Copy code
class Foo<Bar>(
        initial: Bar?,
        val barClass: KClass<Bar>
) {

    private val internal: Any? = initial

    fun baz(): Bar? {
        val i = internal
        return if (i is Bar) i
        else null
    }
}
Type argument is not within its bounds
Expected: Any
Found: Bar
d
`Bar`'s implicit upper bound is
Any?
.
That's nullable.
b
Ah, so I change
Foo<Bar>
to
Foo<Bar: Any>
d
Yes
b
I suppose I still internalize
?
as “wrapped in an `Optional`”
It’s hard switching so rapidly back and forth between Kt and Swift