Hi, I have another question, this time about generics :)
public class Test {
private val <T : Any> field = HashSet<T>()
fun test() {
field.clear()
}
}
field.clear() doesn’t work because the compiler can’t infer what T : Any is, and asks me to specify it. Why can’t I just call that method? Is there any way of me to specify the type?(Any is just an example, my real code is a bit more complex but with the same issue)
What is going to change with the compiler knowing that information? L already has a bound, and calling that method with a ddifferent value for L is not going to change anything, is it?
So I've found a workaround that works for now, but I guess you're going to remove this from working in the future?
private val <L : Any, T : MyThing> field = HashMap<Class<T>, MutableList<OtherThing<L, T>>>()
override fun reset() { val temp:HashMap<Class<MyThing>, MutableList<OtherThing<Any, MyThing>>> = field; temp.clear()
}
Is not very nice, but it works. I still don’t understand why the compiler doesn’t do this (replace L with its upper bound) but you might have some reasons why not.
My question is, if this stops being available in the future, can I do something today to make this work (without the workaround) that will be supported in 1.0? Or this won’t be supported at all? I hope it is, because it’s very useful in some cases…
First of all, the code you are trying to write is incorrect by nature:
The property is initialized only once, and being able to refer to it pretending that the same collection has different type arguments every time is prone to errors: I could put an Int into in and later try to take a String out, which would definitely fail.
This is why the compiler should prohibit using type parameters of a val in its initializer.
I don't see where you can put an Int and get a String back, My collection contains Class objects and lists of OtherThing. The only reason I'm using generics in my piece of code is so when you add or retrieve a Class, the type of it should match the collection you get back. I guess L: Any can be removed, as it's doing nothing, but still I don't understand where you can add Ints to get Strings :)
val foo1: HashMap<Any, Int> = foo
val foo2: HashMap<Any, String> = foo
foo1[“key”] = 1
println(foo2[“key”].length())
This throws an exception. In your particular case it may not be possible (I’m not sure), because of the nature of Class<T>, but the compiler knows nothing about the special nature of it, and should reject this code as dangerous.
Ok, so you were referring a different code than mine, and about the nature of my workaround as well. I understand the current status of this is a bit broken as you masterfully explained with this example, but I still think there should be some way of doing this. If you check my example, I think it's very solid, but I'll try to find another way of doing it, or just use "unsafe" code, casting everywhere...
What I’m trying to do is store a map of Class objects and list of KMemberFunction1 instances, so I can call them on those objects, as something like a plugin system. Generics in this case are helping me force the caller to specify a correct link between the passed Class object and the function (a call looks like “system.register(this, MyPlugin::class, ::callbackMethod)” which is not perfect, but very short and concise :D)
Thank you for your explanations, they are mostly welcome