Report a bug
If you spot a problem with this page, click here to create a Bugzilla issue.
Improve this page
Quickly fork, edit online, and submit a pull request for this page. Requires a signed-in GitHub account. This works well for small changes. If you'd like to make larger changes you may want to consider using a local clone.

Named Parameters

Version 1
Created 2016-01-23
StatusDraft
Last modified 2016-01-23
Author Jacob Carlborg

Abstract

This document describes a simple form of named parameters

Rationale

Sometimes it can be very useful to be able to use named parameters. It mostly increases the documentation at the call site.

Rect createRect(int x, int y, int width, int height);
createRect(0, 0, 200, 200);

In the above example it’s not so easy to see at the call site what the different arguments mean. In what order should the coordinate and size be passed?

Another typical example is with boolean arguments:

void sendRequest(Request req, bool log);
sendRequest(req, true);

Again, at the call site it can be difficult to remember what the boolean flag means.

Supporting named parameters directly in the language prevents the need to add workarounds with weird looking syntax like https://dlang.org/phobos/std_typecons.html#.Flag.

Description

This is a proposal for a simple form of named parameters.

Simple Example

Simple example of declaring and calling a function with named parameters:

Rect createRect(int x:, int y:, int width:, int height:);
createRect(x: 0, y: 0, width: 200, height: 200);

Rules

  1. Any parameter that is supposed to be nameable at the call site needs to be explicitly declared as such. This is required because otherwise the parameters of all exist functions would become part of the API
  2. It’s legal mix named and non-named parameters, both when declaring a function and calling the function
  3. It’s optional to name the parameters when calling a function declared with named parameters
  4. It’s not legal to change the order of the arguments at the call site when using the named parameter syntax. This simplifies the function overloading rules (no change is required)
  5. A named parameter at the call site will not conflict with any other symbol with the same name
  6. For the initial version it’s not legal to declare a variadic parameter as a named parameter. This restriction might be lifted in the future
  7. Combining a template specialization with a named parameter requires a space between the two colons
  8. It’s not legal to overload a function purely based on the parameter names. The overloading rules do not change with this proposal

Syntax

A new syntax is added to be used when declaring a function that should be callable with named parameters:

Rect createRect(int x:, int y:, int width:, int height:);

Each parameter that should be able to be named at the call site is required to end with a colon.

Calling a function using the named parameter syntax:

createRect(x: 0, y: 0, width: 200, height: 200);

Prefix the function arguments with the name of the parameter, a colon is used to separate the name of the parameter from the vale of the argument.

The same can be applied to templates:

struct Array(ElementType:) {}
Array!(ElementType: int) array;

Examples

Rect createRect(int x:, int y:, int width:, int height:);
createRect(0, 0, 200, 200);

The above code would compile since it’s still perfectly fine to call a function declared with named parameters using the standard calling syntax.

createRect(x: 0, y: 0, width: 200, height: 200);

The above is an example of calling the same function with named parameters.

Mixing named and regular parameters:

createRect(0, 0, width: 200, height: 200);

Using symbols with the same parameter names is legal:

createRect(x: x, y: y, width: width, height: height);

Changing the order when using the named parameter syntax is not legal:

createRect(width: 200, height: 200, x: 0, y: 0); // error

Mixing regular and named parameters when declaring a function:

void sendRequest(Request req, bool log:);

Calling the above function:

sendRequest(req, log: true);

Compiles as expected.

sendRequest(req: req, log: true);

The above would be an error since the “req” parameter is not declared as a named parameter.

Named parameters combined with default values:

void foo(int a: = 3, int b: = 4);
foo();
foo(a: 5, b: 6);
foo(b: 6); // this is not allowed since it's not legal to reorder the arguments

Templates with named parameters:

struct Array(ElementType:) {}
Array!(ElementType: int) array;
void sendRequest!(bool log:)(Request req);
sendRequest!(log: true)(req);
template isInt(Type:) {}
isInt!(Type: int);

Template specialization with named parameter:

struct Array(ElementType: : Object) {}
Array!(ElementType: Object) array;

Name parameters and uniform function call syntax:

void sendRequest(Request req, bool log:);
req. sendRequest(log: true);

Interfacing with Objective-C

@interface NSObject
- (void)performSelector:(SEL)aSelector
             withObject:(id)anArgument
             afterDelay:(NSTimeInterval)delay;
@end

Bindings for the above Objective-C method could look like:

extern(Objective-C) interface NSObject
{
    void performSelector(SEL aSelector, NSObject withObject:, NSTimeInterval afterDelay:) @selector("performSelector:withObject:afterDelay:");
}

Which then can be called exactly as in Swift:

obj.performSelector("foo:", withObject: obj2, afterDelay: 3);

Breakage

No code is expected to break since all changes are additive. This is enforced by requiring the colons when declaring a function and not allowing to change the order of the arguments when calling a function with named parameters.

This document has been placed in the Public Domain.