- Java doesn't have case classes like Scala
- Writing code for variant type wrappers and visitors is annoying
Last active
August 29, 2015 14:26
-
-
Save patrickhammond/bfad10a75a9b21e1d36c to your computer and use it in GitHub Desktop.
Sample of how we might make variant types suck less with Java. See: https://en.wikipedia.org/wiki/Tagged_union for part of the CS theory.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// App code: These classes that describe the state of executing a query | |
// that we want to consume as a stream of events. | |
public class Loading { | |
} | |
public class Results<T> { | |
final List<T> results; | |
public Results(List<T> results) { | |
this.results = results; | |
} | |
} | |
public class Error { | |
final String reason; | |
public Error(String reason) { | |
this.reason = reason; | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// App code: How we would trigger the code generator | |
@Variant | |
public interface Query { | |
Loading loading(); | |
Results<String> results(); | |
Error error(); | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// API code: The annotation being used...no magic. Just here for reference. | |
@Retention(RetentionPolicy.RUNTIME) | |
@Target(ElementType.TYPE) | |
public @interface Variant { | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// Generated code: nothing special here...just code no one wants to write | |
public final class VariantQuery implements Query { | |
private final Loading loading; | |
private final Results<String> results; | |
private final Error error; | |
public VariantQuery(Loading loading) { | |
this.loading = loading; | |
this.results = null; | |
this.error = null; | |
} | |
public VariantQuery(Results<String> results) { | |
this.loading = null; | |
this.results = results; | |
this.error = null; | |
} | |
public VariantQuery(Error error) { | |
this.loading = null; | |
this.results = null; | |
this.error = error; | |
} | |
@Override | |
public Loading loading() { return loading; } // Typically not used? | |
@Override | |
public Results<String> results() { return results; } // Typically not used? | |
@Override | |
public Error error() { return error; } // Typically not used? | |
void accept(VariantQueryVisitor visitor) { | |
if (loading != null) { | |
visitor.visitLoading(loading); | |
return; | |
} | |
if (results != null) { | |
visitor.visitResults(results); | |
return; | |
} | |
if (error != null) { | |
visitor.visitError(error); | |
return; | |
} | |
} | |
public interface VariantQueryVisitor { | |
void visitLoading(Loading loading); | |
void visitResults(Results<String> results); | |
void visitError(Error error); | |
} | |
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
// ------------------------------------------------------------------------ | |
// App code: How we would use this in app code | |
Observable<VariantQuery> observable = Observable.just( | |
new VariantQuery(new Loading()), | |
new VariantQuery(new Results<>(Arrays.asList("A", "B"))), | |
new VariantQuery(new Results<>(Arrays.asList("C", "D")))); | |
observable.subscribe(new Action1<VariantQuery>() { | |
@Override | |
public void call(VariantQuery variantQuery) { | |
// Visitor implementation *should* be a variable vs | |
// constantly instantiated like this, but for now this | |
// is easier to follow | |
variantQuery.accept(new VariantQueryVisitor() { | |
@Override | |
public void visitLoading(Loading loading) { | |
// Show a progress indicator | |
} | |
@Override | |
public void visitResults(Results<String> results) { | |
// Display (or add to existing) results | |
} | |
@Override | |
public void visitError(Error error) { | |
// Show an error | |
} | |
}); | |
} | |
}); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment