-
Notifications
You must be signed in to change notification settings - Fork 46
Description
What happened?
In the apollo codebases, we use unions pretty heavily and on the whole they're pretty great for compile-time safety and forcing devs to consider implications of changes everywhere. That being said, the verbosity of visitors is pretty frustrating from a readability perspective. Building visitors using the new shorthand builders is a lot better than the long anonymous classes, but limitations Java's type inference seems to require us to specify return types upfront so we get stuff like this. It also frustrates me that performance sensitive codepaths jump through indirection to avoid constructing and allocating a visitor on every invocation.
return reportedServiceState.accept(ReportedServiceState.Visitor.<ApolloReportedServiceState>builder()
.assetServer(assetServerReportedServiceState -> ...)
.blueGreen(blueGreenReportedServiceState -> ...)What did you want to happen?
With LTS Java 17 arriving in a couple of months (14th Sep GA), we'll get access to Sealed Classes and a preview of pattern matching for switch expressions.
This means that java has first-class support for java unions, and I'd really like to be able to take advantage of the improved readability:
static String switchExpression(MyUnion union) {
return switch (union) {
case FooVariant foo -> String.format("foo %s", foo);
case BarVariant bar -> String.format("bar %s", bar);
case BazVariant baz -> String.format("baz %f", baz);
default -> union.toString();
};
}Given how many variants some unions have, I reckon it's probably fine to emit code for these across different files:
sealed interface Celestial
permits Planet, Star, Comet { ... }
final class Planet implements Celestial { ... }
final class Star implements Celestial { ... }
final class Comet implements Celestial { ... }Some open questions are:
- would we keep around a
final class UnknownVariant implements Celestial { ... }to make consumers always acknowledge the possibility that the server might have started returning a new variant which their code wasn't compiled to handle. - should we keep around the
accept(Visitor)method? (I think yes, because it allows a convenient migration)