12

Scala has partial functions which are functions that only apply to some values of the input type, but not all:

val isEven: PartialFunction[Int, String] = {
  case x if x % 2 == 0 => x+" is even"
} 

assert(isEven(10) equalsIgnoreCase "10 is even")
assert(isEven.isDefinedAt(11) == false)

And, even more useful, scala allows the "partialness" to be applied to the sub-type of a trait:

sealed trait BaseTrait

case class Foo(i : Int) extends BaseTrait
case class Bar(s : String) extends BaseTrait

val fooPartialFunc : PartialFunction[BaseTrait, Int] = {
  case f : Foo => 42 + f.i
}

assert(fooPartialFunc(Foo(8)) == 50)
assert(fooPartialFunc.isDefinedAt(Bar("hello")) == false)

What is the equivalent in java 8?

Most google results confuse "partial function" with currying, e.g. "partially applied function".

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
Ramón J Romero y Vigil
  • 17,373
  • 7
  • 77
  • 125
  • 2
    You would probably just use an Optional. Is that the sort of thing that you're looking for? In your case, it would return an optional string. And after you call the function you could check whether the value is present or not. For instance, see https://stackoverflow.com/questions/23454952/uses-for-optional . If that answers your question, maybe this one can be close as a duplicate of that. The questions aren't identical but that answer probably answers this one. – Joshua Taylor Oct 12 '18 at 21:05
  • @JoshuaTaylor This doesn't help you to test whether a function `isDefinedAt` a value, *before* evaluating it. – Andrey Tyukin Oct 12 '18 at 21:06
  • @AndreyTyukin that's correct the syntax is a little bit different. But determining whether an arbitrary function is defined for some input probably means evaluating the function at least a little bit. How does Scala determine whether the function is defined at, to use OP's example, 11 without actually checking whether 11 modulo 2 equal 0? I'd say that syntactic differences aside, and optional is going to be the closest thing in Java. – Joshua Taylor Oct 12 '18 at 21:09
  • @JoshuaTaylor No, `val pf: PartialFunction[Int, Unit] = { case 42 => System.exit(42) } ; pf.isDefinedAt(42)` will not evaluate `pf`, not even a tiniest little bit ;) The `if x % 2 == 0` is a *guard expression* on the left hand side of the match, when you invoke `isDefinedAt`, it doesn't touch the right hand side. That's exactly the point: `PartialFunction` is composed of both the predicate that determines the domain and a (separate!) piecewise function definition on that domain. A function that simply returns `Optional` is strictly weaker than `PartialFunction`s. – Andrey Tyukin Oct 12 '18 at 21:15
  • Just curious: In which actual usage is this sort of "partialness" useful? The trait example seems pretty hard to understand for someone who is Scala-illiterate or less savvy with functional programming. – Mick Mnemonic Oct 12 '18 at 21:16
  • @AndreyTyukin How can Scala determine whether that guard, ` x % 2 == 0` is true or not, and thus whether the function has a value for `11` without evaluating it? But that's no different from any language with `if`. In Java, writing `if (x % 2 == 0) { /* a */ }`, the `/* a */` doesn't get executed if `x % 2 == 0` is false. – Joshua Taylor Oct 12 '18 at 21:19
  • @JoshuaTaylor By evaluating *only the guard*, and *without touching the right hand side of the function*? I've already given a single-line example above. It will happily return `true`, without exiting the JVM. – Andrey Tyukin Oct 12 '18 at 21:20
  • 1
    @AndreyTyukin You do make a good point, though, in that Scala's partial functions can return true for isDefinedAt, even when evaluating the function would actually throw an exception. So I think a truer analog would be an `Optional>`. – Joshua Taylor Oct 12 '18 at 21:31

3 Answers3

6

A Java 8 Idiomatic, But Not Entirely Faithful, Approach

The most typical thing in Java 8 is going to be the Optional class:

import static org.hamcrest.Matchers.equalTo;
import static org.hamcrest.Matchers.is;
import static org.junit.Assert.assertThat;

import org.junit.Test;

import java.util.Optional;

public class OptionalAsPartialFunction {

  Optional<String> isEven(final int x) {
    return Optional.of(x)
        .filter(i -> i % 2 == 0)
        .map(i -> i + " is even");
  }

  @Test
  public void example() {
    assertThat(isEven(10).get(), equalTo("10 is even"));
    assertThat(isEven(11).isPresent(), is(false));
  }
}

If you're familiar with Optional, then you'll see that the string concatenation i + " is even" is only evaluated if the filter condition, i % 2 == 0, is true. If you're not familiar with with Java's Optional, you can write this out with an if/else, as well:

Optional<String> isEven(final int x) {
  if (x % 2 == 0) {
    return Optional.of(x + " is even");
  } else {
    return Optional.empty();
  }
}

This should make is completely clear that the string concatenation is evaluated if and only if the guard condition evaluates to true.

A More Faithful, But Less Idiomatic (in Java) Approach

With the naive approach, you're calling the function, and getting an Optional which either contains the actual value of the function or it doesn't. But Scala's PartialFunction is a little bit more complex. From the documentation you linked to:

Even if isDefinedAt returns true for an a: A, calling apply(a) may still throw an exception, so the following code is legal:

val f: PartialFunction[Int, Any] = { case _ => 1/0 }

So we'd like to be able to check whether the function "is defined" for an input, even if trying to compute if for that input would actually be an error.

So a more faithful approach would be to use an Optional<Supplier<...>>. The outer Optional lets you know whether there's a computation to perform, and the inner Supplier lets you perform that computation (if you choose). So the example would become:

  Optional<Supplier<String>> isEven(final int x) {
    return Optional.of(x)
        .filter(i -> i % 2 == 0)
        .map(i -> () -> i + " is even");
  }

or, with an if/else:

Optional<Supplier<String>> isEven(final int x) {
  if (x % 2 == 0) {
    return Optional.of(() -> x + " is even");
  } else {
    return Optional.empty();
  }
}

and isPresent() still checks whether the function is defined, but get() will now return the Supplier whose get() method will actually compute the value:

  @Test
  public void example() {
    assertThat("isPresent() checks whether the function is defined for the input", //
        isEven(10).isPresent(), equalTo(true));
    assertThat("get() returns the supplier that actually computes the value", //
        isEven(10).get().get(), equalTo("10 is even"));
    assertThat("isPresent() checks whether the function is defined for the input", //
        isEven(11).isPresent(), is(false));
  }
Community
  • 1
  • 1
Joshua Taylor
  • 84,998
  • 9
  • 154
  • 353
  • *"then you'll see that the string concatenation i + " is even" is only evaluated if the filter condition, i % 2 == 0, is true"* - once again, that's not the problem. The problem is that the concatenation is evaluated **every time** the filter condition is true. Try implementing the `System.exit` example, you'll see that the `Optional` approach does not allow you to obtain `isDefinedAt` `true`, because it simply shuts down the JVM before returning anything at all. – Andrey Tyukin Oct 12 '18 at 21:26
  • 1
    @AndreyTyukin You're right. I'm updating my answer to provide my initial approach as the "this is what you're most likely to see in Java", but to then add a more faithful `Optional>` approach. – Joshua Taylor Oct 12 '18 at 21:33
  • 1
    @AndreyTyukin Yes, there was also an "in progress..." farther up. I didn't want to lose what I'd already been typing. :) Does the second approach capture Scala's PartialFunction a bit more precisely? – Joshua Taylor Oct 12 '18 at 21:45
  • I would argue that this is the exact opposite of what the OP is asking about. The OP is asking about using partial functions, you are talking about changing partial functions to total functions by changing their result type. You can do that in Scala as well, Scala also has an idiomatic `Option` type in its standard library, and in fact, for things like `Map[Key, Value].get`, the idiomatic return type *is* `Option[Value]`. – Jörg W Mittag Oct 15 '18 at 07:12
5

Java does not seem to provide PartialFunctions directly, but it provides a few interfaces that you can use to define your own PartialFunction<X,Y>. A PartialFunction<X, Y> is essentially just:

  • a Predicate<X> for testing whether a value of type X is in the domain
  • Function<X, Y> for the actual function definition that is invoked if the function is defined for the argument value.

Below, I've sketched how you could make use of Predicate and Function to implement PartialFunction. In this sketch, I defined only the three most important methods:

  • isDefinedAt is essentially just Predicates test.
  • apply invokes test and, if successful, invokes the applyIfDefined, which represents the "actual body of the function" (right hand side of cases in Scala)
  • orElse is a demonstration of a compositional structure different from ordinary function composition, just as a proof of concept

Here is the full Java code:

import java.util.function.*;

abstract class PartialFunction<X, Y> implements Predicate<X>, Function<X, Y> {
  public boolean isDefinedAt(X x) {
    return this.test(x);
  }
  public Y apply(X x) {
    if (isDefinedAt(x)) {
      return applyIfDefined(x);
    } else {
      throw new IllegalArgumentException("Match error on " + x);
    }
  }
  public abstract Y applyIfDefined(X x);

  public PartialFunction<X, Y> orElse(PartialFunction<X, Y> fallback) {
    PartialFunction<X, Y> outer = this;
    return new PartialFunction<X, Y>(){
      public boolean test(X x) {
        return outer.test(x) || fallback.test(x);
      }
      public Y applyIfDefined(X x) {
        if (outer.isDefinedAt(x)) {
          return outer.applyIfDefined(x);
        } else {
          return fallback.apply(x);
        }
      }
      @Override
      public Y apply(X x) {
        return applyIfDefined(x);
      }
    };
  }

  public static void main(String[] args) {
    PartialFunction<Integer, String> f = new PartialFunction<Integer, String>() {
      public boolean test(Integer i) {
        return i % 2 == 0;
      }
      public String applyIfDefined(Integer i) {
        return i + " is even";
      }
    };
    PartialFunction<Integer, String> g = new PartialFunction<Integer, String>() {
      public boolean test(Integer i) {
        return i % 2 == 1;
      }
      public String applyIfDefined(Integer i) {
        return i + " is odd";
      }
    };
    System.out.println(f.apply(42));
    try {
      System.out.println(f.apply(43));
    } catch (Exception e) {
      System.out.println(e);
    }
    PartialFunction<Integer, String> h = f.orElse(g);
    System.out.println(h.apply(100));
    System.out.println(h.apply(101));
  }
}

The output of the above example is:

42 is even
java.lang.IllegalArgumentException: Match error on 43
100 is even
101 is odd

If you wanted to use it with some kind of "case-classes", you could do this too, but for that, you would have to provide an implementation of the case classes first.

Andrey Tyukin
  • 43,673
  • 4
  • 57
  • 93
2

Vavr brings to Java a lot of cool stuff from Scala.

If you ok with 3rd party libraries, it could be the best choice.

@Test
public void test() {
    PartialFunction<Integer, String> isEven =
            Function1.<Integer, String>of(integer -> integer + " is even")
                    .partial(integer -> integer % 2 == 0);

    Assert.assertEquals("10 is even", isEven.apply(10));
    Assert.assertFalse(isEven.isDefinedAt(11));
}

More complex example you can find here

Alexander Pankin
  • 3,787
  • 1
  • 13
  • 23