Hi!
Today I've ran into some problem when using vavr. I have some method which is simply a dispatcher of events.
private Change applyChange(DomainEvent event) {
return Match(event).of(
Case($(instanceOf(ChangeDeployedOnDevEnvEvent.class)), this::apply),
Case($(instanceOf(ChangeAccepted.class)), evt -> this.apply(BO_ACCEPTED, evt)),
Case($(instanceOf(AcceptanceIgnored.class)), evt -> this.apply(NEW, evt)),
Case($(instanceOf(ChangeSignedOffOnQA.class)), evt -> this.apply(SIGNED_OFF_ON_QA, evt)),
Case($(instanceOf(ChangeDeployedOnQA.class)), evt -> this.apply(DEPLOYED_ON_QA, evt)),
Case($(instanceOf(ChangeAcceptedByQA.class)), evt -> this.apply(ACCEPTED_BY_QA, evt)),
Case($(instanceOf(ChangeDeploymentOnQAFailed.class)), evt -> this.apply(SIGNED_OFF_ON_QA, evt)),
Case($(), o -> {
throw new IllegalArgumentException("Unsupported event");
})
);
}
Problem is that when I have 8 cases like in example the code won't compile - I'm getting such compilation error:
error: method of in class Match<T> cannot be applied to given types;
return Match(event).of(
^
required: Case<? extends DomainEvent,? extends R>[]
found: Case<ChangeDeployedOnDevEnvEvent,Object>,Case<ChangeAccepted,Object>,Case<AcceptanceIgnored,Object>,Case<ChangeSignedOffOnQA,Object>,Case<ChangeDeployedOnQA,Object>,Case<ChangeAcceptedByQA,Object>,Case<ChangeDeploymentOnQAFailed,Object>,Case<Object,Object>
reason: inferred type does not conform to upper bound(s)
inferred: DomainEvent
upper bound(s): ChangeSignedOffOnQA,DomainEvent,Object
where R,T are type-variables:
R extends Object declared in method <R>of(Case<? extends T,? extends R>...)
T extends Object declared in class Match
1 error
> Task :compileJava FAILED
Problem disappears when I remove one of Cases. Any ideas if I'm doing something wrong?
vavr version - 0.9.2
@garlicsauce I think this is a limitation of the type inference engine in javac. Eclipse compiles the code just fine. In similar cases like this, when the code itself is valid, but it fails to compile because of some type inference limitation, it's usually solved by a simple addition of a type witness to help out the compiler:
return Match(event).<Change> of(
Case($(instanceOf(ChangeDeployedOnDevEnvEvent.class)), this::apply),
Case($(instanceOf(ChangeAccepted.class)), evt -> this.apply(BO_ACCEPTED, evt)),
Case($(instanceOf(AcceptanceIgnored.class)), evt -> this.apply(NEW, evt)),
Case($(instanceOf(ChangeSignedOffOnQA.class)), evt -> this.apply(SIGNED_OFF_ON_QA, evt)),
Case($(instanceOf(ChangeDeployedOnQA.class)), evt -> this.apply(DEPLOYED_ON_QA, evt)),
Case($(instanceOf(ChangeAcceptedByQA.class)), evt -> this.apply(ACCEPTED_BY_QA, evt)),
Case($(instanceOf(ChangeDeploymentOnQAFailed.class)), evt -> this.apply(SIGNED_OFF_ON_QA, evt)),
Case($(), o -> {
throw new IllegalArgumentException("Unsupported event");
})
);
With the added type witness, this code compiles with javac as well.
Thanks @nfekete! Now this works fine.
Most helpful comment
@garlicsauce I think this is a limitation of the type inference engine in
javac. Eclipse compiles the code just fine. In similar cases like this, when the code itself is valid, but it fails to compile because of some type inference limitation, it's usually solved by a simple addition of a type witness to help out the compiler:With the added type witness, this code compiles with
javacas well.