1

I am new vavr so I don't know if I am missing some basic stuff but i am doing pattern matching which Java does not have right now. After debugging I realized that vavr matches all the Cases but will not execute the value if a Supplier is provided if the case condition does not match. Is that right?

for eg:

public Enum Days{
    MONDAY,
    TUESDAY...
}

String s = Match(days).of(
        Case($(Days.MONDAY), "monday"),
        Case($(Days.TUESDAY), "tuesday")
);

In the above example if days = MONDAY it calls the CASE method passes the enum value and checks if there is a match. In this case its a match so it will return "monday". I was hoping the pattern matching will be terminated since we got the match. But it turns out it goes inside Case method again for TuESDAY also , the pattern does not match so the value remains "monday" but I was wondering is there a way to stop the pattern matching once the condition is met.

Sachin Jain
  • 97
  • 1
  • 10

2 Answers2

9

Vavr Match will stop at the first matching Case and will return the associated value.

What you are experiencing is just standard Java behavior. Arguments are eagerly evaluated before being passed to a method, so, when you write

Case(Pattern, retValExpression)

and retValExpression is an expression, the retValExpression expression will be eagerly evaluated before even passing it over to the API.Case factory method. If you want the retValExpression expression to be lazily evaluated only when the Case is matching, you need to convert it to a Supplier by creating a lambda expression:

Case(Pattern, () -> retValExpression)

In this case, the lambda expression () -> retValExpression will only be evaluated when the corresponding Case is matching.

If your problem lies with the Pattern expressions getting evaluated eagerly, you can apply the same technique to convert them to lazy evaluation by supplying a lambda for a Predicate:

Case($(value -> test(value)), () -> retValExpression)
Nándor Előd Fekete
  • 6,988
  • 1
  • 22
  • 47
  • Hi Nandor, I did that I supplied a Supplier and it worked and yes () -> retValExpression is only evaluated when the Case matches. But my question was different. I meant to ask that say even if we have a Supplier as the value for all the Case it still checks to see if there is a match even if the match was found. So it will not execute the Supplier if the match was not found but it still calls the Case method to check every match even though it will only execute the value for only the match since it is a Supplier. Hope my question make sense – Sachin Jain May 02 '19 at 21:26
  • It doesn't really make sense to me. Maybe you have the same issue of eager evaluation in the `Pattern` expressions you construct the `Case` values with. If so, it's the very same thing happening as I described in my answer, only in a different place. `Match.of` **will** stop at the first match, I just looked it up in the source code. See [relevant source code](https://github.com/vavr-io/vavr/blob/cdce0c463b208c43c830edfa11a298552f1ce477/vavr/src-gen/main/java/io/vavr/API.java#L5575-L5584). – Nándor Előd Fekete May 02 '19 at 21:55
  • I updated my answer to show an example of pattern expressions that are lazy lazily evaluated, if that helps. – Nándor Előd Fekete May 02 '19 at 22:02
1

I disagree: as soon as a case matches, it stops evaluating other cases, assuming you write your cases in lazy mode (e.g. with Predicates and Suppliers). The problem comes from Java being eager by default on its arguments evaluation, this has nothing to do with Vavr.

Here's a counter-example of what you claim. Please note:

  • the matchers are lazy (written with Predicate)
  • the values are lazy (written with Supplier)

.

public class Main {
  public static void main(String[] args) {
    var result = Match("foo").of(
        Case($(choice("one")), () -> result("1")),
        Case($(choice("two")), () -> result("2"))
    );

    System.out.println(result);
  }

  static Predicate<String> choice(String choice) {
    return string -> {
      System.out.println("Inside predicate " + choice);
      return true;
    };
  }

  static String result(String result) {
    System.out.println("Inside result " + result);
    return result;
  }
}

When executed, this yields:

Inside predicate one

Inside result 1

1

Please note that neither the second predicate nor the second result were ever evaluated.

Community
  • 1
  • 1
Sir4ur0n
  • 1,753
  • 1
  • 13
  • 24