Named/labeled/keyword arguments are useful in Python and OCaml, but in the D language they were proposed by DIP1030 and adopted three years ago.
- Suggestion https://github.com/dlang/DIPs/blob/master/DIPs/accepted/DIP1030.md
- Implementation status https://github.com/dlang/dmd/pulls?q=named+arguments
Currently, templates are not supported, but recent DMDs -preview
allow you to try out these features without any flags. The verification environment this time is DMD2.106.0.
function call
Now let's take an example of basic usage.
import std;
void f(int a, int b) {
writeln("f(a: ", a, ", b: ", b, ")");
}
void g(int a = 0, int b) {
f(a: a, b: b);
}
void main() {
f(a: 1, b: 2);
f(a: 1, 2);
f(1, b: 2);
1.f(b: 2);
// f(b: 1, 2); error
// 2.f(a: 1); error
g(b: 2);
// g(1); error
}
Basically, there are benefits such as being able to freely specify the order in which they are called, and if the names have meaning, they are easier to read. Unlike Python, it's nice to have more freedom, such as being able to declare parameters with default values before formal parameters without default values, and unnamed parameters being allowed to come after named parameters.
Speaking of function-like things, structures and classes can also be constructed with named arguments.
struct S {
int a;
int b;
}
struct SS {
S s;
int c;
}
class C {
this(int a, int b) {
writeln("C(a:", a, ", b:", b, ")");
}
}
void main() {
S s = {a: 1, b: 2};
writeln(s);
// writeln(S{a:1, b:2}); // error
writeln(S(a:1, b:2));
SS ss = {{a: 1, b: 2}, c: 3};
writeln(ss);
writeln(SS(S(a: 1, b: 2), c: 3));
C c = new C(a:1, b:2);
}
Until now, structures had static initialization {}
using curly braces, but it was not possible to write something like this, and it was a hassle to assign it to some variable and then call it. Named arguments can avoid this. It is also possible to call constructors with named arguments, something that was not possible with classes. foo(S{a:1, b:2})S s = {a:1, b:2}; foo(s)
Currently, named arguments for templates have not been implemented, so no one knows about this feature without any announcement, but we believe that it will revolutionize library design even now.
For example, it is a use case that requires building with a name like HTML.
string html(string lang, string inner) {
return "<html lang=\"" ~ lang ~ "\">" ~ inner ~ "</html>";
}
string img(string src, string alt) {
return "<img src=\"" ~ src ~ "\", alt=\"" ~ alt ~ "\" />";
}
unittest {
html(lang: "ja", img(src: "hello.png", alt: "hello image"));
}
Or, functions in fields such as linear algebra and machine learning have a large number of arguments, and are useful when only a part of them needs to be changed (example of optax.adam)
void adam(float[] params, float[] states, float lr = 1e-4, float beta1 = 0.9, float beta2 = 0.999, float eps=1e-08, float eps_root=0.0);
unittest {
adam(params, states, beta2: 0.98);
}
A design that strictly favors named arguments like OCaml's Core is also interesting https://opensource.janestreet.com/core/