Pretty please: Named arguments

Bekenn leaveme at alone.com
Sun Feb 27 23:03:46 PST 2011


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?


More information about the Digitalmars-d mailing list