In the previous post Daan van Berkel again made clear that a fluent API is so much more readable than the “regular” API’s. Unfortunately a lot of projects do not have the luxury of being able to convert their code to the fluent paradigm. But there are some easy improvements possible, one of them would be the introduction of named parameters.
Let me first start with a simple example:
Well, there is nothing wrong with that code, except as an outsider you have no clue what it is doing exactly. What do the two booleans indicate? This can only be solved by a round trip to the documentation. A fluent API would fix this:
But a lot of codebases cannot simply be converted to a fluent API, and fluent API’s are not easy to get right in the first place. Some developers improve bad readability by adding inline comments like so:
show(false /*modal*/, true /*center*/);
That surely improves readability, but it also is very dangerous, because there is no validation that the comments actually match the meaning of the parameters. (Did I just now make an argument against comments, in contrast to my previous blog? Yes I did.) So what actually is needed is something like compiler checked comments; named parameters.
This looks a lot more readable than the first example. What would happen here is that, given that the called method has parameter information available, the compiler would match that against the specified names. If they do not match, or no parameter information is available, named parameters would cause a compiler error. So there cannot be ‘incorrect comments’.
But if the compiler knows what parameters are expected and which are provided, then it can be smart about their sequence: it can rearrange the provided parameters to match the expected. So the compiler can rearrange this call to make it work correctly:
The compiler knows the order of the parameters and at compile time can rearrange them to the correct order, in the end the resulting byte code should still be ‘just’ the old style call:
This approach is a compiler-only enhancement and perfectly backwards compatible. It improves readability, and allows for changes in the parameter sequence to not cause problems.
A point of attention is when changes are being made to parameters inside a call. In this situation reorder-than-evaluate has different results compared to evaluate-than-reorder. I believe the last is the most natural option, meaning that any expressions are evaluated before the parameters are reordered, so the parameter values match the sequence in the source code. For example assume a method “call(int p1, int p2)”:
int a = 0; // parameters in the correct order: object.call(a++, a); // call(0,1) object.call(p1:=a++, p2:=a); // call(0,1) // changing the order of the parameters: object.call(p2:=a, p1:=a++); // call(0,0) evaluate than reorder object.call(p2:=a, p1:=a++); // call(0,1) reorder than evaluate
What you see is that reorder-than-evaluate (4th call) has no influence on the effective method call, while evaluate-than-reorder (3rd call) results in a different call. Changing the order of the parameters should have obvious consequences. So even though the 4th call is identical to the 2nd (changing the order of the parameters at the caller has no effect), this is not the preferred behavior. Changing the order of the parameters at the caller should have obvious consequences; the “a++” happens after p2 has its value assigned, so the 3rd call (evaluate-than-reorder) is the preferred behavior.
A possible issue is the situation where a SNAPSHOT version of a jar contains parameter info, but the actual released jar does not; this would cause compiler errors. But I’d suggest that Java starts including parameter info per default anyhow, I know ctrl-space in IDE’s will greatly benefit from that as well.