Coupling in ExtentLocal
Holo The Sage Wolf
holo3146 at gmail.com
Thu Jul 28 20:11:17 UTC 2022
Hello core-libs devs,
The ExtentLocal <https://bugs.openjdk.org/browse/JDK-8263012> proposal adds
a new way to transfer arguments to methods, e.g. (taken from project’s loom
git
<https://github.com/openjdk/loom/blob/2bf3cbcf3254a08ca9d1c20ed14e0976660351b8/src/jdk.incubator.concurrent/share/classes/jdk/incubator/concurrent/ExtentLocal.java#:~:text=target%3D%22ExtentLocal%23newInstance%22%20%3A-,*%20%20%20private%20static%20final%20ExtentLocal%3CCredentials%3E%20CREDENTIALS%20%3D%20ExtentLocal.newInstance()%3B,*%20%20%20%7D,-*%20%7D>
)
private static final ExtentLocal<Credentials> CREDENTIALS =
ExtentLocal.newInstance();
Credentials creds = ...
ExtentLocal.where(CREDENTIALS, creds).run(() -> {
...
Connection connection = connectDatabase();
...
});
...
Connection connectDatabase() {
Credentials credentials = CREDENTIALS.get();
...
}
I have a question about the proposal, why not allow try-with-resources with
this API?
private static final ExtentLocal<Credentials> CREDENTIALS =
ExtentLocal.newInstance();
Credentials creds = ...// Hopefully one day Java will support
anonymous variables in "try-with-resource" to get rid of the "var _ ="
part// note that we still can introduce several binding with chaining
".where" without introducing several dummy variablestry(var _ =
ExtentLocal.where(CREDENTIALS, creds)) { // maybe have a new method
instead of "where" that returns some wrapper class, so
ExtentLocal.Carrier won't need to implement AutoClosable
...
Connection connection = connectDatabase();
...
}
...
Connection connectDatabase() {
Credentials credentials = CREDENTIALS.get();
...
}
The syntax of .where(...)....where(...).run(...) is nice, but it is weird
that we “introduce variables” from a different clause then the run (I know
it is only bindings, but it acts similar enough), the syntax of
try-with-resources is already well known to introduce new variables.
Another advantage is the ability of “catch” block without increasing
nesting:
try {
ExtentLocal.where(CREDENTIALS, creds).run(() -> {
Connection connection = connectDatabase();
});
} catch (...) {
...
}
versus
try(var _ = ExtentLocal.where(CREDENTIALS, creds)) {
Connection connection = connectDatabase();
} catch (...) {
...
}
(Another solution to this is too add .catch method to ExtentLocal.Carrier
to handle exceptions, but this will cause problems with call vs run)
Further furthermore, one can combine it with structured concurrency
<https://openjdk.org/jeps/428>:
public Response handle(Credentials creds) throws ExecutionException,
InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure();
var _ = ExtentLocal.where(CREDENTIALS, creds)) { //
functionally this binding is part of the scope
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join().throwIfFailed();
return new Response(user.resultNow(), order.resultNow());
}
}
Instead of doing something like:
// If this solution is possible at all, if the Credentials are a field
in the object then you need to introduce some method to use "handle()"
with the correct Extent binding, or wrap the body of "handle()" inside
of the method "handle()" which needlessly increase nestingspublic
Response handle(Credentials creds) throws ExecutionException,
InterruptedException {
return ExtentLocal.where(CREDENTIALS, creds).call(this::handle)
}
public Response handle() throws ExecutionException, InterruptedException {
try (var scope = new StructuredTaskScope.ShutdownOnFailure()) {
Future<String> user = scope.fork(() -> findUser());
Future<Integer> order = scope.fork(() -> fetchOrder());
scope.join();
scope.throwIfFailed();
return new Response(user.resultNow(), order.resultNow());
}
}
Before saying that I shouldn’t couple handle() to CREDENTIALS, note that
findUser and fetchOrder are already coupled to it, in fact the use of
private ExtentLocal variable introduce coupling pretty much by definition
(which is the intended use case
<https://github.com/openjdk/loom/blob/fibers/src/jdk.incubator.concurrent/share/classes/jdk/incubator/concurrent/ExtentLocal.java#:~:text=An%20%7B%40,nest).>,
although I can think on some use cases with public ExtentLocal).
Now, I do really like the where-run syntax, but I see a lot of merits in
allowing also try-with-resources as well.
Thanks for the read,
Yuval Paz
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mail.openjdk.org/pipermail/core-libs-dev/attachments/20220728/3ea0b538/attachment-0001.htm>
More information about the core-libs-dev
mailing list