I'm not able to wrap my head around this. I am at dis-ease with this type declaration I came across in our codebase. Can someone please help me understand this?
public interface CodeReviewRequest<Q extends CodeReviewRequest<Q>> {
....
}
I'm not able to wrap my head around this. I am at dis-ease with this type declaration I came across in our codebase. Can someone please help me understand this?
public interface CodeReviewRequest<Q extends CodeReviewRequest<Q>> {
....
}
This is actually a common tactic in the Java language. For example, look at the class definition for Enum.
Whenever you have an Interface or an Abstract Class in Java, you can use this circular declaration to assert the following claim: Any class that directly implements/extends me must use either themselves as the type parameter or another type that implements/extends me.
This is particularly useful because it limits what can be placed into the type parameter, while still leaving it open for extension.
For example, consider the following code.
public class ExtendsTest
{
public interface User<Q extends User<Q>> { ... }
public class ReadUser implements User<ReadUser> { ... }
public class ReadWriteUser implements User<ReadWriteUser> { ... }
public class Admin extends ReadWriteUser { ... }
public class StringUser implements User<String> { ... } //this fails because String is not an acceptable cornerstone type
}
By using this tactic, you are essentially creating a gated community of possible types that can be used in the type parameter. That gated community can expand as freely as you like, but they all must implement the interface using either themselves, or another class that implements the interface. And you might notice - the type that sort of acts like the cornerstone (besides the interface) is CommonUser
. When using this gated community tactic, you will always end up with one or more types at the top that use this circular declaration to define themselves. Thus, you can have several mini communities within your gated community. It's a powerful way to set boundaries through typing and extension, while still letting things be fairly free and open ended.
EDIT - After a good discussion with @newacct, I should really mention that interface User<Q extends User<Q>>
is (as far as I can tell) equivalent to interface User<Q extends User<?>>
. So either/or on the syntax. My points about the benefits still stand, but it's important to clarify the syntax.
`, so it does not demonstrate a case where this bound is useful. The only case where I can think of this bound being useful is if `User` had a method that returned the type `Q` (or returned a type that allowed you to get `Q`), in which case if you have a `User– newacct Jan 09 '22 at 18:11`, you can call the method to get a `User`, and call the method again to get a `User`, etc., without knowing what `Q` is.
`, but the goal is to restrict the types of potential child classes that implement from this interface. By limiting what can be considered a User, we have put up walls that prevent logical bugs further down the line. Using my updated example, you can see how just using `User– davidalayachew Jan 09 '22 at 22:28` as opposed to `User>` can allow for functionality that we would not otherwise want.
>` which has a method `Q getMyManager()`, then the `Q extends User` part is indeed useful as it allows you to use the result of `getMyManager()` as a `User`, without knowing what `Q` is (although `User– newacct Jan 13 '22 at 19:18>` would also achieve that). So in this case, it is possible to write code that compiles with the bound that would not compile without it. But in the example in your answer, `User` doesn't have a method that returns `Q`, so I don't think it's possible to write code that compiles with the bound that would not compile without it.
>` and method `Q getMyManager()`, you would either have a value of a specific type of user, or you have a `User>` without knowing what the type of user is (because if you knew what `Q` is, then why not just use `Q` instead of `User– newacct Jan 13 '22 at 19:25`?). So in the latter case it would still be true that "it forces you to play with only the methods guaranteed by `User`" on the result of `getMyManager()`.
>` is about as useful as my original idea of `User– davidalayachew Apr 06 '22 at 04:50>`. I mistakenly assumed that the question mark would allow undesirable types to be used there. And yes, my example given wasn't great, but the point I meant to make was that you can better restrict the class type parameter if you use `interface User>` as opposed to just `interface User`. Thank you for catching and pointing that out, I have edited my answer now to reflect this fact.