Skip to content

Commit 5b18301

Browse files
authored
Update index.html
1 parent 5606ef2 commit 5b18301

File tree

1 file changed

+94
-35
lines changed

1 file changed

+94
-35
lines changed

Diff for: docs/index.html

+94-35
Original file line numberDiff line numberDiff line change
@@ -118,6 +118,12 @@ <h2>Intro</h2>
118118
_assert(result instanceof Result, "Expected a result but found " + result);
119119
}
120120

121+
function _assert_allowed(name) {
122+
if (_globalAllowed) {
123+
_assert(_globalAllowed.has(name), "Not allowed to call function: " + name);
124+
}
125+
}
126+
121127
class Result {
122128
constructor(value, exception) {
123129
this._value = value;
@@ -172,29 +178,36 @@ <h2>Intro</h2>
172178
return newFuture;
173179
}
174180

175-
static _completed(result) {
181+
static _completedResult(result) {
176182
var f = new CompletableFuture();
177-
f._internalComplete(result);
183+
f._completeResult(result);
178184
return f;
179185
}
180186

181187
// fun: Exception => Future
182188
exceptionallyCompose(fun) {
183189
_assert(_globalLanguageLevel >= 12, "Requires Java 12+");
190+
_assert_allowed("exceptionallyCompose");
184191
return this
185-
.thenApply(x => CompletableFuture.completedFuture(x))
186-
.exceptionally(fun)
187-
.thenCompose(x => x);
192+
._thenApply(x => CompletableFuture.completedFuture(x))
193+
._exceptionally(fun)
194+
._thenCompose(x => x);
188195
}
189196

190197
// fun: (Value, Value) => Value
191198
thenCombine(other, fun) {
192-
return this.thenCompose(x => other.thenApply(y => fun(x, y)));
199+
_assert_allowed("thenCombine");
200+
return this._thenCompose(x => other._thenApply(y => fun(x, y)));
193201
}
194202

195203
// fun: Exception => Value
196204
exceptionally(fun) {
197-
return this.handle((value, exc) => {
205+
_assert_allowed("exceptionally");
206+
return this._exceptionally(fun);
207+
}
208+
209+
_exceptionally(fun) {
210+
return this._handle((value, exc) => {
198211
if (exc != null) {
199212
return fun(exc);
200213
} else {
@@ -205,7 +218,12 @@ <h2>Intro</h2>
205218

206219
// fun: Value => Value
207220
thenApply(fun) {
208-
return this.handle((value, exc) => {
221+
_assert_allowed("thenApply");
222+
return this._thenApply(fun);
223+
}
224+
225+
_thenApply(fun) {
226+
return this._handle((value, exc) => {
209227
if (exc != null) {
210228
throw exc;
211229
} else {
@@ -216,12 +234,22 @@ <h2>Intro</h2>
216234

217235
// fun: Value => Future
218236
thenCompose(fun) {
219-
return this.thenApply(fun)._dereference();
237+
_assert_allowed("thenCompose");
238+
return this._thenCompose(fun);
239+
}
240+
241+
_thenCompose(fun) {
242+
return this._thenApply(fun)._dereference();
220243
}
221244

222245
// fun: (Value, Exception) => Value
223246
handle(fun) {
224-
return this._handle(result => {
247+
_assert_allowed("handle");
248+
return this._handle(fun);
249+
}
250+
251+
_handle(fun) {
252+
return this._handleResult(result => {
225253
if (result.isValue()) {
226254
return Result.value(fun(result._value, null));
227255
} else {
@@ -231,15 +259,15 @@ <h2>Intro</h2>
231259
}
232260

233261
// fun: Result => Result
234-
_handle(fun) {
262+
_handleResult(fun) {
235263
var newFuture = new CompletableFuture();
236264
this._addCallback(result => {
237265
try {
238266
var result2 = fun(result);
239267
_assert_result(result2);
240-
newFuture._internalComplete(result2);
268+
newFuture._completeResult(result2);
241269
} catch (err) {
242-
newFuture._internalComplete(Result.exception(err));
270+
newFuture._completeResult(Result.exception(err));
243271
}
244272
});
245273
return newFuture;
@@ -252,12 +280,12 @@ <h2>Intro</h2>
252280
if (result.isValue()) {
253281
var future = result._value;
254282
_assert_future(future);
255-
future._addCallback(result2 => newFuture._internalComplete(result2))
283+
future._addCallback(result2 => newFuture._completeResult(result2))
256284
} else {
257-
newFuture._internalComplete(result);
285+
newFuture._completeResult(result);
258286
}
259287
} catch (err) {
260-
newFuture._internalComplete(Result.exception(err));
288+
newFuture._completeResult(Result.exception(err));
261289
}
262290
});
263291
return newFuture;
@@ -293,15 +321,15 @@ <h2>Intro</h2>
293321
}
294322

295323
complete(value) {
296-
this._internalComplete(Result.value(value));
324+
this._completeResult(Result.value(value));
297325
}
298326

299327
completeExceptionally(exc) {
300328
_assert_exc(exc);
301-
this._internalComplete(Result.exception(exc));
329+
this._completeResult(Result.exception(exc));
302330
}
303331

304-
_internalComplete(result) {
332+
_completeResult(result) {
305333
if (this._result == null) {
306334
this._result = result;
307335
}
@@ -357,7 +385,7 @@ <h2>Intro</h2>
357385
}
358386

359387
for (var i = 0; i < inputs.length; i++) {
360-
inputFutures[i]._internalComplete(inputs[i]);
388+
inputFutures[i]._completeResult(inputs[i]);
361389
}
362390

363391
if (!outputFuture.isComplete()) {
@@ -464,6 +492,7 @@ <h2>Intro</h2>
464492
}
465493

466494
_globalLanguageLevel = lesson.maxLanguageLevel;
495+
_globalAllowed = lesson.allowedSet;
467496

468497
var testResults = runTests(userFunction, lesson.compiledSolution, lesson.inputs);
469498

@@ -509,6 +538,11 @@ <h2>Intro</h2>
509538
lessondiv.append($('<h3>').text(lesson.title))
510539
lessondiv.append($('<p>').text(lesson.text))
511540

541+
if (lesson.allowed) {
542+
lesson.allowedSet = new Set(lesson.allowed)
543+
lessondiv.append($('<p>').text("Allowed methods: " + lesson.allowed.join(", ")));
544+
}
545+
512546
try {
513547
lesson.compiledSolution = compile(lesson.solution, lesson.inputs);
514548
} catch (err) {
@@ -550,59 +584,82 @@ <h2>Intro</h2>
550584

551585
var lessons = [
552586
{
553-
title: "Lesson 1",
554-
text: `Let's start by transforming a future into a new future.`,
587+
title: "Simple transform",
588+
text: `Return a new future that adds a "!" to the input value`,
555589
inputs: [
556590
"input"
557591
],
558592
code: `return input.thenApply(v -> v);`,
559593
solution: `return input.thenApply(v -> v + "!");`,
594+
allowed: ["thenApply"],
560595
maxLanguageLevel: 12,
561596
},
562597
{
563-
title: "Lesson 2",
598+
title: "Exception handling",
564599
text: `Now it's time to handle exceptions!
565600
Your code should do the same thing as before, but if the input future
566601
has an exception, your result future should convert the error string
567602
to "Error: " + exception`,
568603
inputs: [
569604
"input"
570605
],
571-
code: `// Hint: use the exceptionally-method
572-
return input.thenApply(v -> v);`,
606+
code: `return input.thenApply(v -> v);`,
573607
solution: `
574608
return input
575609
.thenApply(v -> v + "!")
576610
.exceptionally(e -> "Error: " + e.getMessage());`,
611+
allowed: ["thenApply", "exceptionally"],
577612
maxLanguageLevel: 12,
578613
},
579614
{
580-
title: "Lesson 3: Combining futures",
581-
text: `Now we are going to get two futures as input. Your job is to return a future that is the concatenation of the values.`,
615+
title: "Combining futures",
616+
text: `Now we are going to get two futures as input. Your job is to return a future that is the concatenation of the values. You are only allowed to use thenCombine`,
582617
inputs: [
583618
"first", "second"
584619
],
585-
code: `// Hint: use thenCombine
586-
return null`,
620+
code: `return null`,
587621
solution: `
588622
return first.thenCombine(second, (a,b)->a+b);`,
623+
allowed: ["thenCombine"],
624+
maxLanguageLevel: 12,
625+
},
626+
{
627+
title: "Combining futures: part 2",
628+
text: `Same as previous, but now you have to solve it only using thenCompose and thenApply`,
629+
inputs: [
630+
"first", "second"
631+
],
632+
code: `return null`,
633+
solution: `
634+
return first.thenCompose(a -> second.thenApply(b -> a+b));`,
635+
allowed: ["thenCompose", "thenApply"],
589636
maxLanguageLevel: 12,
590637
},
591638
{
592-
title: "Lesson 4: Combining many futures",
639+
title: "Combining multiple futures",
593640
text: `Now we are going to get three futures as input. Your job is to return a future that is the concatenation of the values.`,
594641
inputs: [
595642
"first", "second", "third"
596643
],
597-
code: `// Hint: use thenCompose and thenApply
598-
return null`,
644+
code: `return null`,
599645
solution: `
600646
return first.thenCompose(a -> second.thenCompose(b -> third.thenApply(c -> a + b + c)));`,
601-
// Alternative: first.thenCombine(second, (a,b)->a+b).thenCombine(third, (a,b)->a+b)
647+
allowed: ["thenCompose", "thenApply"],
648+
maxLanguageLevel: 12,
649+
},
650+
{
651+
title: "Combining multiple futures: part 2",
652+
text: `Same as before, but now you have to use thenCombine and produce intermediate values`,
653+
inputs: [
654+
"first", "second", "third"
655+
],
656+
code: `return null`,
657+
solution: `return first.thenCombine(second, (a,b)->a+b).thenCombine(third, (a,b)->a+b)`,
658+
allowed: ["thenCombine"],
602659
maxLanguageLevel: 12,
603660
},
604661
{
605-
title: "Lesson 5: Retry on exceptions",
662+
title: "Retry on exceptions",
606663
text: `Now we are going to simulate a retry on exception. To simplify things, the retry logic is represented by the future called retry.`,
607664
inputs: [
608665
"input", "retry"
@@ -611,10 +668,11 @@ <h2>Intro</h2>
611668
return null`,
612669
solution: `
613670
return input.exceptionallyCompose(exc -> retry);`,
671+
allowed: ["exceptionallyCompose"],
614672
maxLanguageLevel: 12,
615673
},
616674
{
617-
title: "Lesson 6: Retry on exceptions",
675+
title: "Retry on exceptions: part 2",
618676
text: `Same as the previous lesson, but now you are not allowed to use methods defined in Java 12+.`,
619677
inputs: [
620678
"input", "retry"
@@ -625,6 +683,7 @@ <h2>Intro</h2>
625683
return input.thenApply(v -> CompletableFuture.completedFuture(v))
626684
.exceptionally(exc -> retry)
627685
.thenCompose(f -> f);`,
686+
allowed: ["thenApply", "exceptionally", "thenCompose"],
628687
maxLanguageLevel: 11,
629688
},
630689
];

0 commit comments

Comments
 (0)