The Java 9 named parameter pitch

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:

    component.show(false, true);

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:

    component.modal(false).centered(true).show();

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.

    show(modal:=false, center:=true);

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:

    show(center:=true, modal:=false);

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:

    component.show(false, true);

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.

Advertisements

12 thoughts on “The Java 9 named parameter pitch

  1. Hello, (and sorry for my poor english)

    There is a big problem with this: the parameter name becomes as important as the method signature.

    The simple act of changing the name of a parameter can cause source incompatibility, without any possibility to do otherwise (with classes / methods can always use the deprecation to do this).

    1. I don’t consider that a big problem, but a possible drawback. The question is if the drawback outweighs the gain, to me it does. Changing the name of a parameter could be quite a thing; say you change the one in the example from “centered” to “leftAligned”; that is quite a semantic difference but the original code and the inline comment example will still compile. Wouldn’t it be good that the compiler would detect such a major change? You are right that if you change it from “centered” to “centering”, in that case the change would be a nuisance.

      I think parameter names should be part of the signature; it denotes the meaning of the passed value.

  2. I am talking about changed like “centered”->”centering”, or most commons with bad-named parameters like simple letters one (“c”->”centered”).

    For example, if I want to change this method :
    public void setName(String s)
    into this:
    public void setName(String newName)

    It could introduce source-incompatibility with methods that used it with named parameters : setName(s:=”text”);
    Especially that EDI could generate such code automatically (and unreasonably).

    It could be a problem in large and massively used librairy (like Jakarta Commons…).

    1. Yes, and I still consider it only a minor drawback. Publishing a method with a parameter named “s” or “c” is not something that should be done anyhow. So to me that is not a strong argument.
      But there is nothing preventing the coder to call the method the old style, without named parameters. That will still work of course, otherwise it would not have been backwards compatible. If you don’t like it, don’t use it.

      1. Yes but there are a lot of API with “one-letter” parameters, event in the standard API like String.contains(CharSequence s).
        The simple fact of having named’s parameter will stop developers to “correct” naming their parameters because it will be “source-incompatible”…

        It is not a question of liking or not this notation.
        When you publish an API you have no idea how it will be used by others developers.
        Event if yours methods are not intended to be used with named’s parameters, you can not prevent other developers to do so.

        I think this can be critical in some ways, and it must be considered…

        Perhaps by allowing API designers specify whether their methods can be used like that or not, for example via an annotation :

        @NamedParameters public void show(boolean modal, boolean center)

  3. This is not what i want to say…

    By introducing named’s parameters on all method, it also blocks the renaming parameters of all methods of all existing libraries in the Java world, because renamming a parameters will be a “source-incompatible” change.

    I think it is best to limit it to a few methods (that was the purpose of the annotation).

    1. When you change a function or class name you’d go through the same amount of trouble, why should parameter names be any different?

      The example you mentioned with 1 letter parameters, that is usually common for functions with 1 arguments, in which case the role of the argument is known and there is no need for named parameters, named parameters are for functions with many parameters and if you look at those in common API’s you’d see they usually have nice and descriptive names.

      The only thing I fear from making parameter names part of the function signature is if they used that for overloading too, if that ever happens then god have mercy on us all…

      1. 1. Trouble is different for parameter names, because after that you cannot rename any parameter names without potential “source incompatibility”.
        With method names you can use @Deprecated to “rename” the method…

        2. The problem if you add named parameter à-la-C# (by a compile-time syntaxic sugar like said in this article), it will be possible to use it on any method, even with 1 argument.
        So the simple fact of renaming a parameter will be a source of potential source incompatibility.

  4. That’s a nice feature to have. You don’t need to create sophisticated builders, you only need to choose apropriate parameter names.

    However tome the killer feature for Java 9 would be Lombok integration. No more boilerplate! I can dream, right?

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s