Reusing a "generic object" with different types


I’m wondering whether it would be possible to use an object of a generic class with different type parameters. Yes, I know, it sounds a bit strange since type parameters have to be concrete to create an object (or in other words: the class is generic, the object not).

However, in my case and since the value of the type parameter gets erased anyway, I tried to do something like this:

val policy = RetryPolicy<Any>()
    .withBackoff(10, 1800, ChronoUnit.SECONDS)

As you can see the actual return type (Any in this case) is not relevant for this specific setup of a Failsafe RetryPolicy. To safe some memory, but honestly mainly out of curiosity, I tried to reuse the policy object with concrete types:

fun <T> create(): RetryPolicy<T> = policy as RetryPolicy<T> // unchecked cast!

This function would be called like this:

create<String>().abortIf { predicate: String -> false }

The predicate is of the correct type String instead of Any, as declared in the policy object. However, IntelliJ warns me about an “unchecked cast” in my create function. I know that it shouldn’t matter in this case, but it makes my approach somewhat less elegant.

Is there any better idea?


the actual return type ( Any in this case) is not relevant for this specific setup

That is not exactly true when you add a predicate that depends on the return value being a String. How do you expect your policy to behave, if the operation in question returns something that is not a String? In particular, how do you expect the following code to behave?

val policy = RetryPolicy<Any>()
(policy as RetryPolicy<String>).abortIf { /* something that only works for Strings */ }
FailSafe.with(policy).get { 42 } // Should this abort?
1 Like

You’re right, @Varia. I thought that RetryPolicy would be an immutable object and that methods like abortIf would create a new instance. However, since that isn’t the case, my little thought experiment just doesn’t make much sense (if it ever made sense :wink: ).