Skip to content

Commit 7ffa0de

Browse files
committed
Beef up and comment the test case
1 parent 91710fe commit 7ffa0de

File tree

2 files changed

+87
-17
lines changed

2 files changed

+87
-17
lines changed

build.sbt

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,3 +10,12 @@ sourceGenerators in Compile <+= sourceManaged in Compile map { dir =>
1010
}
1111
Seq(write("F", CodeGen.factory)) ++ (0 to 22).map(n => write("F" + n, CodeGen.fN(n))) ++ (1 to 22).map(n => write("P" + n, CodeGen.pN(n)))
1212
}
13+
14+
sourceGenerators in Test <+= sourceManaged in Test map { dir =>
15+
def write(name: String, content: String) = {
16+
val f = dir / "scala" / "runtime" / "test" / s"${name}.java"
17+
IO.write(f, content)
18+
f
19+
}
20+
Seq(write("TestApi", CodeGen.testApi))
21+
}

src/test/java/scala/runtime/test/Test.java

Lines changed: 78 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,40 +4,101 @@
44
package scala.runtime.test;
55

66
import scala.runtime.*;
7+
import static scala.runtime.test.TestAPI.*;
78

89
public class Test {
910
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:
1027
new F1<String, String>() {
1128
public String apply(String s) { return s; }
1229
};
13-
F1<String, String> f1 = (String s) -> s;
1430

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+
};
1635

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
2038

21-
F1$mcII$sp f3 = (int i) -> i;
39+
// F1 is a subclass of Function1:
40+
scala.Function1<String, String> f2 = f1;
2241

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);
2546

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);
2750

28-
needFunction1(F.f1(x -> x.toUpperCase()));
29-
needProc1(F.p1(x -> x.toUpperCase()));
51+
// f1.apply("");
3052

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;}));
3389

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;}));
3592
}
3693

37-
static void needProc1(scala.Function1<String, BoxedUnit> f1) {
94+
private static void sideEffect() {
3895
}
3996

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;
42103
}
43104
}

0 commit comments

Comments
 (0)