Consider the following line from a project I'm playing around with:

        HRESULT hr = m_Device.Present(null, null, null, null);

Quick: What behavior does that third argument specify? If you said, "Well, /obviously/, that's a handle to an alternative destination window for the render operation; by passing null, you're choosing not to provide an alternative render target." then... well, gee, I have no answer to that.

With named arguments, it becomes a bit easier to understand:

HRESULT hr = m_Device.Present(pSourceRect: null, pDestRect: null, hDestWindowOverride: null, pDirtyRegion: null);

If I remember right, Python has this (optional) feature; I'm not aware of anyone ever complaining about it. It also nicely provides a solution to the bool argument problem: http://blogs.msdn.com/b/oldnewthing/archive/2006/08/28/728349.aspx

But wait, there's more!

Named arguments get a +1 synergy bonus with default arguments. When using parameter names to specify arguments, the order in which those arguments are passed no longer matters. Imagine if the Present() method above provided the default argument null for each parameter:

interface IDirect3DDevice9 : IUnknown
{
        ...
HRESULT Present(const(RECT)* pSourceRect = null, const(RECT)* pDestRect = null, HWND hDestWindowOverride = null, const(RGNDATA)* pDirtyRegion = null);
        ...
}

We can do this in the D binding without running afoul of any linkage issues, and it simplifies the Present() call for its most common usage, which I think is a good thing. Now, let's say I'm doing something special; suppose I'm not worried about source and destination rectangles or dirty regions, but I do want to supply a different render target. With named arguments, that's easy to do without making things messy:

        HRESULT hr = m_Device.Present(hDestWindowOverride: hOverride);

Named arguments should also play nicely with positional arguments:

        auto wrappedString = wrap(reallyLongString, colmuns: 120, tabsize: 4);

Lastly, wouldn't be an entirely new feature; D already supports named arguments for static struct initializers. I merely propose sharing the love with normal functions and struct literals.

Here are the rules I have in mind:

1) Named arguments are not a replacement for positional arguments. Arguments fall into three categories: positional, named positional, and named non-positional. An argument is positional if no name is supplied. An argument is named positional if a name is supplied and its position matches the parameter's position in the function declaration. An argument is named non-positional if a name is supplied and either a) its position does not match the parameter's position in the function declaration, or b) it is immediately preceded by a named non-positional argument.

2) No positional argument may appear after a named non-positional argument.

3) Named non-positional arguments may appear in any order.


Potential problems: The only problems I can foresee here are variations on the situation when there are two (or more) versions of a function with the same number, type, and names of parameters, but in non-matching order, like this:

void func(int a, char b);
void func(char b, int a);

In such a case, the compiler should diagnose an error if named arguments are employed.

Thoughts?

Reply via email to