Vavr: Code won't compile when Match has more than 7 Cases

Created on 7 Jun 2018  路  2Comments  路  Source: vavr-io/vavr

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

question

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:

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.

All 2 comments

@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.

Was this page helpful?
0 / 5 - 0 ratings