Generics is such a big topic, I was struggling wit...
# getting-started
l
Generics is such a big topic, I was struggling with
reified
thing,
in
,
out
,
where
and I thought that's enough. I'm watching `dave leeds`'s video on "reified type parameters" and shocked to see yet another thing
List<*>
now wtf is
*
? yet another wildcard?
m
Example<*>
is
Example<out Bound>
where
Copy code
class Example<T: Bound>(val impl: T)
they're basically Java's raw types but without bypassing all type checks
v
Isn't
Example<*>
more like Java's
Example<?>
and not
Example
? There is no raw type-equivalent in Kotlin, is there?
And as you said you struggle with
reified
. At runtime in JVM-worlds a generic type is erased, so generic type checks are only a compiler check and at runtime you only have the raw type without generic parameter. With Kotlin it is by default the same, at runtime you do not have access to the actual type used for the generic parameter. With
reified
you can use the type. For example this will not work:
Copy code
fun <T> T.getJavaClass() = T::class.java
but this does work:
Copy code
inline fun <reified T> T.getJavaClass() = T::class.java
Or this will work but is an unchecked cast:
Copy code
fun <T> cast(o: Any) = o as T
while this is a type-safe cast:
Copy code
inline fun <reified T> cast(o: Any) = o as T
c
In addition to what everyone else said,
*
means "I don't care what it is".
List<*>
is a list of "I don't know, could be anything". So when you read from it, it behaves as a
List<Any?>
(you don't know what you'll get) and when you write to it, it behaves as a
List<Nothing>
(you don't know what you're alllowed to put in there, so you're allowed to put nothing).
There's also
_
but that just means "hey compiler, I'm too lazy to write the type that goes there, figure it out yourself", it's not special in any other way
v
What do you mean by the last?
val foo: MutableList<_> = mutableListOf("foo")
fails compilation with "Unresolved reference".
c
_
is not legal everywhere, I don't know the exact rule. I think it's mostly when calling something that has ambiguous type parameters.
Copy code
fun <T, U> foo(input: T): U {
    TODO()
}

val a = foo("foo")
// Compilation error: Cannot infer type parameter U. Specify it explicitly.

val b = foo<_, Int>("bar")
Here
T
is most definitely
String
, and the compiler can figure that out itself, but it has no way of knowing what the return type
U
would be
v
I would probably write
val b: Int = foo("bar")
but, yeah, I know that place, but not for the
List<...>
case.
c
Oh yeah,
b: Int
is nicer in this particular example. I usually encounter
_
when using self-types or other recursive type parameters