Subject says it all. Pointers to doc welcome. I don’t understand what this syntax conveys.
fun main(args: Array<String>) {
genericFunc<Int>() // What does this mean?
}
Subject says it all. Pointers to doc welcome. I don’t understand what this syntax conveys.
fun main(args: Array<String>) {
genericFunc<Int>() // What does this mean?
}
With zero context, I’m not sure how accurate my answer will be. But I’ll do my best.
What it looks like to me, is that there exists a function called genericFunc
, and that function is being called. So let’s say your whole code looks like this:
fun main(args: Array<String>) {
genericFunc<Int>() // What does this mean?
}
fun <T : Any> genericFunc() {
println("genericFunc called")
}
When you run your code, it would print out “genericFunc called”.
I’m guessing the bit you’re confused about is the <Int>
bit? Considering it’s called genericFunc
, I’m guessing it’s a function designed to teach you about generics.
You can find the Kotlin documentation about Generics here. There’s also a decent article here that explains Java Generics.
But to give you a quick cheat sheet, generics are also known as type parameters. Basically, it’s a parameter that specifies a type, hence the name. The usual use case for them is collections, like Lists, Sets, Maps, etc. A List is a bunch of objects, right? But usually, you want all of those objects to be the same. If you have a List that contains Strings, integers, objects, booleans… how are you going to write code that handles that List? Every time you get an item out of the List, you’d have to check if it’s a String, integer, object, boolean… so a List has a “type parameter” that says “the type of items stored in this List are this type”. The syntax for specifying the type is to use angled brackets, and put the type inside the brackets.
Is this what you were asking? Does this help? If not, give me more details about what your actual question is, and I’ll have another go at answering it.
I’m interested in the meaning of the syntax described on the subject line - what does that denote? Although I’m somewhat familiar with the concept of Generics in other languages, I am new to Kotlin. I’m reading through some tutorials to learn the language. Your sample code is pretty similar to what I was looking at. I get how you can apply it to a list, so that the compiler will ensure that all list elements are constrained to a particular type. But I’m not yet getting how it applies to a function invocation, particularly one being called with no arguments/parameters.
In your code sample genericFunc is being invoked with no parameters, and no return value is being captured either. So how does the Generic apply here? Your code example, like the one I was reading, seems to take no advantage of Generics, and would function identically without them. Am I missing something?
Can you maybe provide a slightly more detailed example that illustrates how Generics can influence the behavior please?
You are correct, it doesn’t make that much sense if we don’t pass or return anything. See this example:
fun <T> getFirst(list: List<T>): T = list[0]
If we call this function on a list of strings, we get a string. If we call it on a list of integers, we get an integer.
We just specify the T
manually. It is as simple as that. Sometimes T
can’t be inferred from arguments, sometimes we like to adapt T
to our needs. For example, listOf<String>()
returns a list of strings.
Thanks - that use of Generics is clearer to me. What would the invocation look like? Do you have to apply the Type qualifier to the function invocation, such as in the Subject line? Or was that qualifier only necessary due to lack of an actual parameter from which the type could be derived?
I’m interested in your final example listOf<String>()
.
How can the function body determine the type it was invoked with, if there’s no parameter?
For example, how would you control behavior within genericFunc<Int>()
and genericFunc<String>()
, if both invocations were to return a list of objects of the specified type?
Can you query T somehow?
In this specific case it doesn’t need to know T
. It creates any list and casts it to List<String>
.
I guess my question is - it seems the type specifier is designed such that the function can handle the desired type. Presumably if there’s no argument, then the function needs to know what to do based on the type specified. How can the function determine the specified type?
If it’s as simple as a cast, what would happen if the function returned a list of mixed types? Would that be a runtime error? I thought one purpose of Generics was to allow for compile-time error checking.
Well, as always, the ultimate answer lies in reading the code
So it appears that listOf
is implemented as a Generic, and indeed is as simple as a cast. I’m not sure if this can be entirely checked at compile time, but it’s possible. Also interesting that listOf
, while declared as a Generic, can be called without any type specifier at all (“non-Generic”?), and then does no cast.
Thanks to all who responded.
100%, in the example function I provided, the type parameter is completely useless. I was just demonstrating what the syntax looks like.
No, you can’t query T
.
If you were using a function with a type parameter, but no actual parameters… yeah, you might have to use some kind of cast or something. The idea of generics is to allow for the compiler to know what the type is, so it can validate your code. But if you had this, for example:
fun <T : Any> genericFunc(): T {
return "hello" as T
}
That would be a completely useless function, because it ignores your type parameters. Generally, a function that has a type parameter will either take an argument that uses that type parameter, or it’ll be an extension function that operates on an instance that uses that type parameter.
// identity function, just returns the same item
fun <T> identity(item: T): T {
return item;
}
fun <T> List<T>.firstOrNull(): T? {
// "this" is the list that this function is operating on
if (this.isEmpty()) {
return null
}
return this.first()
}
listOf(1, 2, 3).firstOrNull()
I guess if I was to summarise it, I would say that generics in Kotlin work the same way as they do in Java, and (I assume) the same way they work in any other language. The only exception is reified types, which is definitely something worth learning about, but those aren’t technically generics.