Expressions
Calls
Calling functions and methods, with positional and named arguments, explicit type arguments, and the rules that decide which callable a name refers to.
since 0.1.0-alpha.1linuxwindowswasm
Description
f(args) // function call; the overload is chosen by the argument types
f(x, label: value) // positional arguments first; named arguments may follow in any order
obj.method(args) // method call; the overload is chosen by the argument types
f::<int>(args) // explicit type arguments for a generic function
obj.method::<R>(args) // explicit type arguments for a generic method
A call is resolved as one set of bindings from arguments to parameters. Functions, methods, constructors and attributes all use the same spelling and the same rules. Constructing an object is covered by lang.construction.
Positional arguments come first and bind the parameters from the left. Named arguments (name: value) bind the parameter with that name and may appear in any order after the positional ones. A parameter that receives no argument takes its declared default value.
When a callable has several overloads, the compiler picks the one whose parameter types fit the argument types best; between two equally good fits it prefers the one that needs fewer defaults, and an exact tie goes to the overload declared first.
Positional, named and default arguments, and explicit type arguments
string greet(string name, string greeting) => "${greeting}, ${name}!";
string fmt(string text, int width = 5, string pad = ".") => "${text}${width}${pad}";
T identity<T>(T v) => v;
class Printer {
string show<R>(R v) => "<${v}>";
}
console.writeln(greet("Ada", "Hello"));
console.writeln(greet("Ada", greeting: "Hi"));
console.writeln(greet(greeting: "Hey", name: "Bo"));
console.writeln(fmt("x"));
console.writeln(fmt("x", pad: "!"));
console.writeln(fmt("x", pad: "!", width: 2));
console.writeln(identity::<float>(2));
console.writeln(Printer().show::<int>(5));
Hello, Ada!
Hi, Ada!
Hey, Bo!
x5.
x5!
x2!
2.000000
<5>
Rules
- Positional arguments must precede named arguments. A positional argument after a named one is a compile error.
- A named argument binds the parameter with that name. An unknown name, or a second binding of the same parameter, is an error.
- An omitted parameter takes its declared default. A default must be a compile-time constant and cannot refer to another parameter or to
this. - Explicit type arguments
::<T, ...>follow the complete callee and must be followed by(. They must name exactly as many types as the callable has type parameters, and they are authoritative: an argument whose type conflicts with a parameter that the explicit types pin is a compile error at that argument. - Without a following
(, a::-reached callable is not a call but a method reference. Seelang.method-references.
Which callable does a bare name call
Inside a class body, an unqualified call f(args) is resolved in this order:
- a local variable or parameter of function type named
f; - a callable member of the class named
f, including inherited members, so a bare call in a derived class reaches a base-class method; - a free function named
f.
A callable member shadows a free function of the same name completely. If the member exists but none of its overloads accepts the arguments, the call is an error: it does not fall back to a free function that would have fitted. To reach the free function, qualify it with its namespace (NS::f(args)). A plain data field with the same name as a free function does not shadow it, so a call still reaches the function.
A bare name used as a value, not called, follows a similar order: a local or parameter first, then a data member of the class, including inherited ones and including fields of function type, and only then a global or free function. So inside a class, apply(handler) passes the field handler even when a free function of that name exists.
A class member shadows a free function
string tag(int n) => "free";
string handler(int n) => "free handler";
string apply((int) => string f) => f(1);
class C {
string tag(int n) => "member";
string which() => tag(1);
(int) => string handler = (n) => "field handler";
string run() => apply(handler);
}
console.writeln(C().which());
console.writeln(tag(1));
console.writeln(C().run());
console.writeln(apply(handler));
member
free
field handler
free handler
Examples
string fmt(string text, int width = 5) => "${text}${width}";
console.writeln(fmt(width: 2, "x"));
// error: positional argument after named argument
int f<T>(T x) => 1;
console.writeln(f::<int, string>(3));
// error: call to 'f' expects 1 explicit type argument, got 2
console.writeln(f::<int>("s"));
// error: argument for parameter 'x' has type 'string', expected 'int'
Explicit type arguments on functions and methods
class Mapper {
R wrap<R>(R v) => v;
}
T first<T>(Array<T> xs) => xs.at(0);
console.writeln(first::<string>(["a", "b"]));
console.writeln(Mapper().wrap::<int>(3) + 1);
a
4
Notes
Defaults on parameters whose type is a type variable are not supported.
See also
- Array — An ordered sequence of values of one type,
Array<T>, with value semantics. - Construction — Creating objects by naming the type, choosing a constructor by label, supplying type arguments, and building a class that declares no constructor.