- Antril
- Referencia
- Funciones
Esta página aún no está traducida al español. Leer la versión en inglés
Functions
Antril functions and methods - declarations, parameters, bodies, overloads and how a call is resolved, function values and func types, lambdas and what they capture, and extension blocks.
En esta página
Declaring a function
[attributes] [modifiers] Name[<type parameters>](parameters) [: Result] [into namespace N] body
import System;
// A block body.
Gcd(i64 a, i64 b) : i64
{
loop (b != 0)
{
i64 t = a % b;
a = b;
b = t;
}
return a;
}
// An expression body.
Square(i32 x) : i32 => x * x;
// No result: the function returns nothing.
Report(str label, i64 value)
{
Console.WriteLine(label + ": " + value);
}
Main()
{
Report("gcd", Gcd(84, 36));
Report("square", Square(9));
}
larva run
gcd: 12
square: 81
- The name comes first and the result type last, after
:. Writing the result type first (i32 Square(…)) is error AN0020. - A function declared in a namespace is a free function; one declared in a type is a method (see Members). Both are written the same way.
- Every path of a function with a result must end in
return value;orthrow.return;ends a function without one (AN2001, AN2008, AN2009). - An expression body,
=> expression;, returns the expression's value (or just evaluates it when there is no result). - A function without a body ends in
;. Only bodiless methods of a base class or an interface, and[Import]functions, can leave the body out (AN1027). - Functions cannot be declared inside another function's body; use a lambda there.
| Modifier | Meaning |
|---|---|
static |
A method of the type, not of an object. |
unsafe |
The body may use pointers (see Memory). |
async |
The function returns a task and may await (see Iterators and async). |
virtual, override, final |
Overriding, for methods (see Members). |
| access words | See Access. |
Parameters
Each parameter is a type and a name, separated by commas: (str label, i64 value). Two parameters cannot share a name (AN1024), and a parameter cannot be void (AN1023).
- Value types are passed by copy and objects by reference: a method that changes an object's field changes it for the caller, but assigning a parameter changes only the parameter.
&Tand&mut Tparameters take a borrowed reference, when the borrow checker is on (see Memory).- A parameter can carry attributes:
Deposit([Range(1, 1000)] i32 amount).
Warning
Not yet available:
- default values and named arguments (
Greet(str name, str greeting = "Hello"),Greet(name: "Ana")). Write an overload that calls the full one. variadic T[]parameters that take any number of arguments. Pass an array literal (Sum([1, 2, 3])), or use a pack of type parameters.
Overloads
Functions in the same scope can share a name if their parameters differ:
Describe(i32 x) : str => "the number " + x;
Describe(str s) : str => "the text " + s;
Describe(i32 x, i32 y) : str => "two numbers";
A call picks the overload:
- by the number of arguments;
- then by their types: an overload whose parameters match the arguments exactly wins over one reached through implicit conversions.
Two overloads with the same parameters are error AN1030. A call that no overload takes is AN2057 (or a conversion error when there is only one candidate); a call that two overloads take equally well is AN2058: cast an argument to say which.
Function values
A function is a value of a function type:
| Type | A function that |
|---|---|
func<A, B> : R |
takes an A and a B and returns an R |
func : R |
takes nothing and returns an R |
func<A> |
takes an A and returns nothing |
func |
takes and returns nothing |
A free function, a static method, object.Method (bound to that object) or a lambda becomes a function value where one is expected. When the name is overloaded, the expected type chooses the overload. A function value is called like a function:
import System;
public class Counter
{
i32 start;
public:
new(i32 start) { this.start = start; }
Step(i32 by) : i32 => start + by;
static Triple(i32 x) : i32 => x * 3;
}
Twice(i32 x) : i32 => x * 2;
Twice(f64 x) : f64 => x * 2;
Pick(bool fast) : func<i32> : i32 => fast ? Twice : Counter.Triple;
Main()
{
func<i32> : i32 f = Twice;
func<f64> : f64 g = Twice;
func<i32> : i32 bound = new Counter(10).Step;
Console.WriteLine(f(4) + " " + g(1.5) + " " + bound(5) + " " + Pick(false)(2));
any boxed = f;
func<i32> : i32 back = (func<i32> : i32)boxed;
Console.WriteLine(back(21));
}
larva run
8 3 15 6
42
A function value can be stored in any (it is boxed) and recovered with a cast.
Warning
Not yet available:
- naming a function type,
func Transform(i32 x) : i32;. Write thefunc<…> : Rtype where it is used. - calling a function value with
Invoke(f.Invoke(1)). Call it directly:f(1).
func*<A> : R is a different type: the address of a C function, for interop. See Interop.
Lambdas
A lambda writes a function where a value is expected:
| Form | Example |
|---|---|
| One parameter | x => x * 2 |
| Several | (a, b) => a + b |
| Typed parameters | (i32 a, str b) => b + a |
| No parameters | () => 7 |
| Block body | x => { Console.WriteLine(x); }, x => { return x * 2; } |
The parameter types come from the function type the lambda goes to, or are written. A lambda with untyped parameters where no function type is expected is error AN2100. The result type comes from the body; a block body must return a value on every path when one is expected (AN2001).
import System;
Apply(func<i32> : i32 f, i32 x) : i32 => f(x);
Main()
{
Console.WriteLine(Apply(x => x + 1, 41));
func<i32, i32> : i32 add = (a, b) => a + b;
func<i32> : func<i32> : i32 times = (i32 a) => b => a * b;
Console.WriteLine(add(2, 3) + " " + times(3)(4));
func greet = () => Console.WriteLine("hi");
greet();
i32 total = 0;
func<i32> collect = x => { total = total + x; };
collect(5);
collect(7);
Console.WriteLine(total);
}
larva run
42
5 12
hi
12
A lambda captures the local variables and parameters it uses. It sees them as they are when it runs, and assigning one inside the lambda changes the variable itself, as total above shows. Inside an instance method, a lambda also sees this and the object's members.
Collections take lambdas: List<T> has Where, Map, Any, All, FindIndex, ForEach, RemoveAll and Sort(compare).
Extension blocks
An extension block adds functions to a type that already exists, including primitives, interfaces and types from other libraries:
| Form | Adds |
|---|---|
ext(T name) { … } |
Methods called on values of T. Inside, name is the value the method is called on. |
ext<T : constraint>(T name) { … } |
Methods for every type that meets the constraint. |
static ext(T) { … } |
Static functions called on the type itself: T.F(). |
import System;
public interface IShape
{
Area() : f64;
}
public class Square : IShape
{
public:
f64 Side;
new(f64 Side);
Area() : f64 => Side * Side;
}
ext(i32 n)
{
public:
IsEven() : bool => n % 2 == 0;
}
ext<T : IShape>(T shape)
{
public:
Double() : f64 => shape.Area() * 2;
}
static ext(str)
{
public:
Repeat(str text, i32 times) : str
{
str all = "";
loop (i32 i = 0..times)
all = all + text;
return all;
}
}
Main()
{
Console.WriteLine((4).IsEven());
Console.WriteLine(new Square(3).Double());
Console.WriteLine(str.Repeat("ab", 3));
}
larva run
true
18
ababab
- An extension block goes at the top level of a file or a namespace, and holds functions only: no fields, properties or constructors (AN1075).
- A non-static block names its receiver,
ext(i32 n); a static one does not,static ext(i32)(AN0029). - Its members take access sections like a type's. An extension is found wherever its namespace is visible: imported, or the same namespace.
- A member of the type itself wins over an extension with the same name.
System.Core uses ext<T : bitflag enum>(T flags) to give every bitflag enum HasFlag, With, Without and Toggle.
Editar esta página en GitHub Reportar un problema