Java named parameters re-re-revisited

  • Post category:Java

How long can I extend that “re-” pattern? πŸ˜€ But this post seems to be the last.

What you may be missing is that such a feature creates a new coupling of the names at the declaration site to the names at every (separately compiled) use site, meaning the consequences of alpha-renaming goes from zero to disaster. We can’t pull that kind of switch on people.

Actually there is an existing agreement that renaming of method parameters is without consequence. Specific transforms are called out in JLS as binary compatible.

I had already mentioned my concern about the strong coupling that named parameters introduce in the first revisited post. Even though the coupling is just a strong as when a custom class is used as a parameter, developers simply do not expected this coupling on named parameters. But the fact that the specification defines that renaming parameters names are to be without consequence, makes named parameters a dead end.

And also because something else has changed since 2013… EDI’s:

And that makes the price to pay for adding named parameters not worth it.

That said, it still was fun to let the idea run through one’s head. And likewise it also is fun to see if there is a way to make this work without renaming parameters… What about using the recently added record classes? Consider this a little creative piece of code (aka it will not compile):

public Rectangle(record Parameters(int width, int height) p) {
    this(p.width(), p.height();
}

new Rectangle(new Parameters(100, 200));

Defining an inline record as a parameter is a way to easily step out of the rules that apply to parameters and their name. But the call still is not very readable. Exactly because of that, one of the things that records IMHO have been missing are builders. These could be generated by the compiler as part of a record, or some Maven plugin could be convinced to do that.

public Rectangle(record Parameters(int width, int height) p) {
    ...
}

new Rectangle(Parameters.builder().width(100).height(200).build());

But that does introduce a lot of scaffolding. Maybe it is better to look at double brace initialization, combined with a little inspiration picked up from a post of mr Goetz in project Amber. An empty constructor is required in this situation

public Rectangle(record Parameters(int width, int height) p) {
    ...
}

new Rectangle(new Parameters(){{width = 100; height = 200;}});

And then with a little compiler tuning the Parameter class can be made anonymous and inferred.

public Rectangle(record(int width, int height) p) {
    ...
}

new Rectangle({{width = 100; height = 200;}});

Now optional parameters are not a problem anymore either. In fact mandatory parameters become an issue, so some validation logic must be added somewhere in that initialization code.

public Rectangle(record(int width, @Mandatory int height) p) {
    ...
}

new Rectangle({{height = 200;}});

Or let’s mix in a shortcut notation for defaults, and assume all without defaults are mandatory

public Rectangle(record(int width = 300, int height) p) {
    ...
}

new Rectangle({{height = 200;}});

That’s close enough. πŸ™‚

Leave a Reply