[Correction] Re: [string-templates] Covariant signature of 'process' method
Tagir Valeev
amaembo at gmail.com
Thu Aug 3 11:51:55 UTC 2023
Additional thoughts on this topic.
1. Currently, it looks impossible for the processor to declare several
disjoin exceptions. E.g., I cannot do this:
static class CovariantException implements
StringTemplate.Processor<Integer, Exception> {
@Override
public Integer process(StringTemplate stringTemplate) throws
IOException, SQLException {
return 123;
}
}
public static void main(String[] args) {
CovariantException proc = new CovariantException();
try {
Integer i = proc."hello";
} catch (IOException e) {
// handle
} catch (SQLException e) {
// handle
}
}
I must declare and handle the closest supertype exception (which is
simply java.lang.Exception), which makes the exception handling much
more clumsy, as in this case I will also catch unrelated
RuntimeExceptions. Or I can declare a separate rethrowing
catch(RuntimeException ex), but this is very unfortunate to force
people to do this.
2. Annotations could be added to the process() method and handled by
third-party tools like annotation processors or static analyzers. For
example, Checker framework provides Pure annotation to annotate
methods that don't produce side-effects. We can do this:
static class Covariant implements StringTemplate.Processor<Object,
RuntimeException> {
@Override
@Pure
public Integer process(StringTemplate stringTemplate) {
return 123;
}
}
public static void main(String[] args) {
Covariant proc = new Covariant();
Object i = proc."hello";
}
And we will assume that the static analyzer will respect the
annotation. To do this, a static analyzer should resolve the implicit
call in template expression into Covariant::process. However, Java
compiler resolves it to Processor::process (as covariant return type
is ignored). It sounds really strange to get the return type from the
supermethod while the annotations from the most specific method. Of
course, we cannot put our own annotations to Processor::process.
With best regards,
Tagir Valeev.
On Thu, Aug 3, 2023 at 12:10 PM Tagir Valeev <amaembo at gmail.com> wrote:
>
> Unfortunately, I mixed the sample code. The first code sample in my
> previous letter should read as:
>
> public class Test {
> static class MyProcessor implements
> StringTemplate.Processor<Integer, Exception> {
> @Override
> public Integer process(StringTemplate stringTemplate) {
> return 123;
> }
> }
>
> public static void main(String[] args) {
> MyProcessor proc = new MyProcessor();
> Integer i = proc."hello";
> }
> }
>
> The second sample should read as:
>
> public class Test {
> static class MyProcessor implements
> StringTemplate.Processor<Object, RuntimeException> {
> @Override
> public Integer process(StringTemplate stringTemplate) {
> return 123;
> }
> }
>
> public static void main(String[] args) {
> MyProcessor proc = new MyProcessor();
> Integer i = proc."hello";
> }
> }
>
> Sorry for the confusion.
>
> With best regards,
> Tagir Valeev.
>
> On Thu, Aug 3, 2023 at 12:07 PM Tagir Valeev <amaembo at gmail.com> wrote:
> >
> > Hello!
> >
> > It's possible to create a custom string template with covariant
> > process() method signature. For example, we can relax the throws
> > statement:
> >
> > public class Test {
> > static class MyProcessor<T> implements
> > StringTemplate.Processor<Integer, Exception> {
> > @Override
> > public Integer process(StringTemplate stringTemplate) {
> > return 123;
> > }
> > }
> >
> > public static void main(String[] args) {
> > MyProcessor<String> proc = new MyProcessor<>();
> > Integer i = proc."hello";
> > }
> > }
> >
> > Now, it's not compilable:
> > java: unreported exception java.lang.Exception; must be caught or
> > declared to be thrown
> >
> > However, it's evident and can be statically checked that the exception
> > is not possible.
> >
> > Covariant return type is also possible:
> >
> > public class Test {
> > static class MyProcessor implements
> > StringTemplate.Processor<Integer, Exception> {
> > @Override
> > public Integer process(StringTemplate stringTemplate) {
> > return 123;
> > }
> > }
> >
> > public static void main(String[] args) {
> > MyProcessor proc = new MyProcessor();
> > Integer i = proc."hello";
> > }
> > }
> >
> > Now, it's not compilable:
> > java: incompatible types: java.lang.Object cannot be converted to
> > java.lang.Integer
> >
> > This requires passing exact types through the inheritance hierarchy
> > which might be inflexible and annoying. I may probably want to declare
> > `abstract class AbstractProcessor implements Processor<Object,
> > Throwable>` and have any covariant signatures in subtypes without
> > declaring new type parameters and forward them through the hierarchy.
> >
> > Java has another implicit way to call methods: try-with-resources and
> > AutoCloseable interface. There we have no exception type parameter,
> > but covariant signatures in subclass close() methods are respected at
> > the try-with-resource use sites. Probably it would be more consistent
> > and convenient to respect covariant signatures in string templates as
> > well?
> >
> > With best regards,
> > Tagir Valeev.
More information about the amber-spec-experts
mailing list