Yole, thank you for your prompt answer.
I’ll try to explain it with a simplified example. I hope that this simplification doesn’t distort the real problem. Let’s try…
I’ve a class that retrieves registries from a database. To find these registries, it can use different types of primary keys. This is what I do in Java:
class DatabaseManager {
public <T extends Registry> T find (Object primaryKey)
throws RegistryNotFoundException {
}
}
The RegistryNotFoundException
exception is thrown if the primary key doesn’t exist in the database. I store the primary key in the exception itself, so that it can be handled adequately in an upper layer. For example, that layer could format the key in different ways depending on its type, to show it to the user.
In Java, I would like being able to do this:
class DatabaseManager {
public <K, V extends Registry> V find (K primaryKey)
throws RegistryNotFoundException<K> {
}
}
class StudentEjb {
public void saveScore (Long studentPk, String examPk,
Integer difficultyPk, Integer variationPk, Short score) {}
throws RegistryNotFoundException<Integer>,
RegistryNotFoundException<Long>,
RegistryNotFoundException<String> {
// Code...
Student student = databaseManager.find (studentPk);
Exan exam = databaseManager.find (examPk);
// More code...
}
}
class StudentServlet {
@Override
protected void doGet (HttpServletRequest request,
HttpServletResponse response)
throws ServletException, IOException {
// Code...
try {
studentEjb.saveScore (studentPk, examPk,
difficultyPk, variationPk, score);
} catch (RegistryNotFoundException<Integer> ex) {
// Specific handling for Integers...
} catch (RegistryNotFoundException<Long> ex) {
// Specific handling for Longs...
} catch (RegistryNotFoundException<String> ex) {
// Specific habnling for Strings...
}
}
}
Obviously, this is not possible in Java, because generics are not reified… Neither in Kotlin, I guess. So I’ve just realized that it hasn’t any sense to implement generics in exceptions, as long as they’re not reified. Because there wouldn’t be a way to differentiate between them at runtime.
Anyway, I’ve continued thinking about this issue, and I’ve found out that, if Kotlin finally implemented disjoint unions, one could implement the exception this other way:
typealias PrimaryKey = Integer | Long | String;
class RegistryNotFoundException (val primaryKey: PrimaryKey)
: Exception ("Blah, blah");
And then, do something like this:
typealias PrimaryKey = Integer | Long | String;
protected fun doGet (request: HttpServletRequest,
response: HttpServletResponse) {
try {
studentEjb.saveScore (studentPk, examPk,
difficultyPk, variationPk, score);
} catch (ex: RegistryNotFoundException) {
val pk: PrimaryKey = ex.getPrimaryKey ();
val msg: String = when (pk) {
is Integer ->// Specific handling for Integers...
is Long -> // Specific handling for Longs...
is String -> // Specific handling for Strings...
}
printMessage (msg);
}
}
In case that we forgot to handle one of the types in the where
expression, the compiler could throw an error, as it does with sealed classes, Right? If that’s true, then it would be a very decent alternative to generics in this specific case.
I know that this wouldn’t be as flexible as having true generics in exceptions. But, since we usually know beforehand which types are accepted by our methods, this feature would cover most cases.
What do you opine?