Ah! Mr Goetz has kindly reacted on Twitter to the previous blog post, and lifted a piece of the curtain.
You’re mostly focusing on a non-problem; reordering can be done statically without any runtime performance cost (or semi-statically, if linkage is done with Indy.). That’s not any of the issues.
Developer blindness; focusing on part of one problem and not seeing the rest. Yes. I’m very good at developer blindness, that is why I always ask: “Did I miss anything?”. But that reordering can be done totally statically amazes me. As far as I know going from B-A (order of evaluation) to A-B (order of parameters) takes at least some CPU power. But hey, at no performance cost is good news.
But, spend some time thinking about overload selection and binary compatibility, and when that voice in your head says “we can just disallow that” when you get to the hard bits, recognize that is the siren singing to you.
Overload selection. Of course! The minute you start reordering arguments there may be multiple methods that may fit. For which one are you reordering? Consider the following two overloaded methods.
void go(int a, String b, double c); void go(String b, int a, double c);
Now, if one would write:
go(c=1.0, b="foo", a=2);
Then this call could match any of the two methods, and the compiler would not know for which to reorder the arguments.
But… Is that significantly different from trying to make this call?
go(1.0, "foo", 2);
That call does not match any of the two signatures, and the compilers fails. Why shouldn’t the compiler simply fail in case it can’t find a single matching method? Finding no method, or finding multiple basically is the same issue.
Suppose we set the stakes a bit higher, and add defaults into the mix:
void go(int a=1, String b=null, double c=2.0); void go(String b=null, int a=1, double c=2.0);
Now the “go()” call could work, if only there was a single method that uniquely matched.
We can use a similar technique for named parameter overloading as is often used; use a distinct marker parameter. Currently this has to be a type (this is nicely visible in log4j’s Logger API), and for named parameter that could be a name.
void go(int a, String b=null, double c=2.0); void go(String b, int a=1, double c=2.0); void go(String d);
Notice that the defaults were removed from the first parameters. This now means that this parameter has to be present, it is no longer optional.
go(1); // matches the first method go("foo"); // matches the third go(b="foo"); // matches the second method go(d="foo"); // matches the third method go(c=10.0); // matches none, because the mandatory parameter is missing
Not all overloading signatures are well suited for named parameters. But they’ll always be callable using non-named calls. Which also means the code block below would still not be allowed.
void go(String a); void go(String b);
Named parameters in my interpretation for Java are a decoration onto the existing pattern to increase readability. It’s not like Java has never introduced conceptually incomplete features before, because the benefits outweigh the limitations. (Not saying that this is the case with named parameters.)
But it’s more likely that I’m still not seeing the complete issue.
About binary compatibility; is it a requirement that every existing method should be callable using named parameters? If the compiler can’t match it, then the coder must revert back to old style calls. Named parameters should only be applied to suitable methods. Most methods are not overloaded.
And if log4j intends to ditch their many overloaded methods in the Logger and replace them with versions that use defaults, then people who use the old style can still use them:
void debug(String message, Object p0 = null, Object p1 = null, Object p2 = null, Object p3 = null, Object p4 = null, Object p5 = null, Object p6 = null, Object p7 = null, Object p8 = null, Object p9 = null) debug(message="oops"); debug("oops");
Again, I’m probably missing something big. Or seeing things way too simple. The devil is usually in the detail.