|
4 | 4 | package scala.runtime.test; |
5 | 5 |
|
6 | 6 | import scala.runtime.*; |
| 7 | +import static scala.runtime.test.TestAPI.*; |
7 | 8 |
|
8 | 9 | public class Test { |
9 | 10 | public static void main(String[] args) { |
| 11 | + // Not allowed with Scala 2.10 nor 2.11 |
| 12 | + // "incompatible types: Function1 is not a functional interface" |
| 13 | + // scala.Function1<String, String> f = (String s) -> s; |
| 14 | + |
| 15 | + // Function1 is not a functional interface because it has abstract |
| 16 | + // methods in addition to apply, namely `compose` and `andThen` |
| 17 | + // (which are implemented in Scala-derived subclasses with mixin |
| 18 | + // inheritance), and the specialized variants of apply (also provided |
| 19 | + // by scalac.) |
| 20 | + |
| 21 | + // That's a pity, but we can get pretty close with this library! |
| 22 | + |
| 23 | + // We have to tell javac to use `F1` as the functional interface. |
| 24 | + F1<String, String> f1 = (String s) -> s; |
| 25 | + |
| 26 | + // That's more or less equivalent to the old, anonymous class syntax: |
10 | 27 | new F1<String, String>() { |
11 | 28 | public String apply(String s) { return s; } |
12 | 29 | }; |
13 | | - F1<String, String> f1 = (String s) -> s; |
14 | 30 |
|
15 | | - f1.apply(""); |
| 31 | + // You might have seen this form before: |
| 32 | + new AbstractFunction1<String, String>() { |
| 33 | + public String apply(String s) { return s; } |
| 34 | + }; |
16 | 35 |
|
17 | | - F1<Integer, Integer> f2 = (i) -> i; |
18 | | - f2.apply(0); |
19 | | - f2.apply$mcII$sp(0); |
| 36 | + // However, we can't use `AbstractFunction1` as a functional interface |
| 37 | + // as it is a class. Further |
20 | 38 |
|
21 | | - F1$mcII$sp f3 = (int i) -> i; |
| 39 | + // F1 is a subclass of Function1: |
| 40 | + scala.Function1<String, String> f2 = f1; |
22 | 41 |
|
23 | | - f3.apply$mcII$sp(1); |
24 | | - f3.apply(1); |
| 42 | + // Factory methods in `F` can reduce the verbosity a little: |
| 43 | + // `f1` is actually just an identity method; it only exists to |
| 44 | + // trigger lambda creation using the `F1` functional interface. |
| 45 | + scala.Function1<String, String> f3 = F.f1((String s) -> s); |
25 | 46 |
|
26 | | - P1<Integer> f4 = (i) -> i; |
| 47 | + // Note that javac's type inference can infer the parameter type here, |
| 48 | + // based on the acribed type of `f4`. |
| 49 | + scala.Function1<String, String> f4 = F.f1(s -> s); |
27 | 50 |
|
28 | | - needFunction1(F.f1(x -> x.toUpperCase())); |
29 | | - needProc1(F.p1(x -> x.toUpperCase())); |
| 51 | + // f1.apply(""); |
30 | 52 |
|
31 | | - String s1 = needFunction1Infer(F.f1(x -> x.toUpperCase())).toUpperCase(); |
32 | | - } |
| 53 | + // Specialized variants of the `apply` method are implenented in the |
| 54 | + // functional interface |
| 55 | + F1<Integer, Integer> f5 = (i) -> -i; |
| 56 | + assert(f5.apply(1) == -1); |
| 57 | + assert(f5.apply$mcII$sp(1) == -1); |
| 58 | + |
| 59 | + // as are `curried`, `tupled`, `compose`, `andThen`. |
| 60 | + f3.compose(f3).andThen(f3).apply(""); |
| 61 | + scala.Function2<String, String, String> f6 = F.f2((s1, s2) -> join(s1, s2)); |
| 62 | + assert(f6.curried().apply("1").apply("2") == "12"); |
| 63 | + |
| 64 | + // Functions returning unit must use the `P1`, ... functional interfaces |
| 65 | + // in order to convert a void lamdba return to Scala's Unit. |
| 66 | + // |
| 67 | + // The easiest way to do this is via `F.p1`, .... |
| 68 | + // |
| 69 | + // Note that the lambda has a return type of `void` if the last |
| 70 | + // statement is a call to a `void` returning method, or if it is |
| 71 | + // a `return`. |
| 72 | + scala.Function1<String, BoxedUnit> f7 = F.p1(s -> sideEffect()); |
| 73 | + scala.Function1<String, BoxedUnit> f8 = F.p1(s -> {s.toUpperCase(); return;}); |
| 74 | + |
| 75 | + // Function0 is also available |
| 76 | + scala.Function0<String> f9 = F.f0(() -> "42"); |
| 77 | + assert(f9.apply() == "42"); |
| 78 | + |
| 79 | + // You can go up to 22 (the highest arity function defined in the Scala standard library.) |
| 80 | + assert(acceptFunction1(F.f1(v1 -> v1.toUpperCase())) == "1"); |
| 81 | + acceptFunction1Unit(F.p1(v1 -> sideEffect())); |
| 82 | + acceptFunction1Unit(F.p1(v1 -> {v1.toUpperCase(); return;})); |
| 83 | + |
| 84 | + assert(acceptFunction2(F.f2((v1, v2) -> join(v1, v2))) == "12"); |
| 85 | + acceptFunction2Unit(F.p2((v1, v2) -> {v1.toUpperCase(); return;})); |
| 86 | + |
| 87 | + assert(acceptFunction3(F.f3((v1, v2, v3) -> join(v1, v2, v3))) == "123"); |
| 88 | + acceptFunction3Unit(F.p3((v1, v2, v3) -> {v1.toUpperCase(); return;})); |
33 | 89 |
|
34 | | - static void needFunction1(scala.Function1<String, String> f1) { |
| 90 | + assert(acceptFunction22(F.f22((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) -> join(v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22))) == "12345678910111213141516171819202122"); |
| 91 | + acceptFunction22Unit( F.p22((v1, v2, v3, v4, v5, v6, v7, v8, v9, v10, v11, v12, v13, v14, v15, v16, v17, v18, v19, v20, v21, v22) -> {v1.toUpperCase(); return;})); |
35 | 92 | } |
36 | 93 |
|
37 | | - static void needProc1(scala.Function1<String, BoxedUnit> f1) { |
| 94 | + private static void sideEffect() { |
38 | 95 | } |
39 | 96 |
|
40 | | - static <T> T needFunction1Infer(scala.Function1<String, T> f1) { |
41 | | - return f1.apply(""); |
| 97 | + private static String join(String... ss) { |
| 98 | + String result = ""; |
| 99 | + for (String s : ss) { |
| 100 | + result = result + s; |
| 101 | + } |
| 102 | + return result; |
42 | 103 | } |
43 | 104 | } |
0 commit comments