User defined exceptions
Exceptions are used in Golo, either in the “classical” way (throw and try...catch) or in the more functional Result, which represents errors as exceptions.
User defined exceptions are useful to convey more specific semantic on the kind of error, to encapsulate additional data on the error cause and to define specific behavior polymorphically.
However, there is currently no easy way to define user exceptions directly in Golo, since subtyping is needed.
I suggest an alternate form of GoloStruct extending RuntimeException. This would not yet give subtyping, and thus we would not have an exception hierarchy. However, users could defined type with the same ease of use as the golo struct, but whose instances could be used as exceptions.
Syntactically, this could be defined as:
module Plop
exception MyException = {message, cause, a, b}
The message and cause attribute may be implicit or not, but I think explicit is better, with a compile-time error if the exception does not specify these fields.
This would generate a class like:
package Plop.types;
class MyException extends RuntimeException implements Iterable<Tuple>, Comparable<MyException> {
private Object a;
private Object b;
MyException(String message) { super(message); }
MyException(String message, Throwable cause) { super(message, cause); }
MyException(String, message, Throwable cause, Object a, Object b) {
super(message, cause);
this.a = a;
this.b = b;
}
// Generated methods similar to the ones in structs
// values, equals, hashCode, get, set, iterator, compareTo, frozenCopy, copy, destruct, isFrozen
}
used as:
return Result.error(MyException())
throw MyException("my error message", theCause, 42, "plop")
An other option is to let the user specify the exception superclass (default to RuntimeException), allowing the definition of an exception hierarchy, for instance:
exception MyException(IllegalArgumentException) = {message, cause}
I'm very interested in implementing this feature.
What @yloiseau described is more or less what I had in mind: doing something similar to how structs are being defined.
The subtyping thing is intriguing. I'm not sure we want to enter that area, since that would require compile-time classpath resolution.
The subtyping was just an idea, I didn't though about the compile time resolution. Without subtyping, catching exception will be more cumbersome, but it's indeed a difficult point.
maybe we could allow the subtyping case provided that the super class is fully qualified, as for augmentations; for instance:
exception MyException(java.lang.IllegalArgumentException) = {message, cause}
@jponge did you had time to experiment with this feature?
I've made some progress, but I haven't had time to get back to it recently...