- Antril
- Referencia
- Operadores
Esta página aún no está traducida al español. Leer la versión en inglés
Operators
Declaring operators in Antril - the built-in symbols, new symbols with their precedence and associativity, prefix and postfix operators, increment, conversions, generic operators and operator constraints.
En esta página
A type declares operators with op. An operator is a static, public method of its type that the compiler finds by the types of the operands: no import is needed to use it.
op SYMBOL(T a, T b) : R [precedence(level)] [associativity(kind)] body // binary
op SYMBOL(T a) : R body // one operand, either side
left op SYMBOL(T a) : R body // before the operand: SYMBOL a
right op SYMBOL(T a) : R body // after the operand: a SYMBOL
op (Target)(Source s) body // a conversion
The body is a block or => expression;. Every operator has a result type (AN0023).
import System;
public value Money
{
public:
i64 Cents;
new(i64 Cents);
op +(Money a, Money b) : Money => new Money(a.Cents + b.Cents);
op -(Money a) : Money => new Money(-a.Cents);
op *(Money a, i64 k) : Money => new Money(a.Cents * k);
op ==(Money a, Money b) : bool => a.Cents == b.Cents;
op <(Money a, Money b) : bool => a.Cents < b.Cents;
op ++(Money a) : Money => new Money(a.Cents + 1);
op (i64)(Money m) => m.Cents;
op (Money)(i64 cents) => new Money(cents);
}
Main()
{
Money a = new Money(150);
Money b = new Money(250);
Console.WriteLine((a + b).Cents + " " + (-a).Cents + " " + (a * 3).Cents);
Console.WriteLine((a == b) + " " + (a != b) + " " + (a < b));
a++;
++a;
Console.WriteLine((i64)a);
Money c = (Money)99i64;
Console.WriteLine(c.Cents);
}
larva run
400 -150 450
false true true
152
99
Rules
- An operator is declared inside the type of one of its operands (AN0022 at namespace level).
- It is always
publicandstatic, whatever its section says. - A symbol can be declared for several operand types; the call is resolved like an overload.
op ==gives!=too. On a class, a declaredop ==replaces comparison by identity.- One
op ++(orop --) serves both++xandx++: the variable is replaced by the result;++xhas the new value andx++the old one. - Operators of the primitive types are built in.
- Compound assignment uses the operator:
a += bisa = a + b, and needsop +to give the type ofa(AN2099).
Built-in symbols
These symbols can be declared, with the number of operands shown; they keep the language's precedence:
| Symbol | Operands |
|---|---|
+ - |
one or two |
* / % & | ^ == != < <= > >= |
two |
! ~ |
one |
++ -- |
one |
=, ., =>, ?, .., ..=, -> and ... cannot be operators (AN0021). &&, ||, ??, the shifts and the ranges are not declarable as built-in operators.
New symbols
A program can declare its own symbols: a run of the characters + - * / % & | ^ ~ ! < > = ? @ # $, written without spaces, such as ^^, <=>, <+> or #. A new binary symbol must say how strongly it binds, after its result type (AN1067):
| Clause | Takes |
|---|---|
precedence(…) |
A member of PrecedenceLevel, a number, or a constant member of any integer enum (AN1069). |
associativity(…) |
Associativity.Left (the default), Associativity.Right, or Associativity.None. |
A higher level binds more strongly. The levels of PrecedenceLevel are:
| Level | Value | Built-in operators at that level |
|---|---|---|
Assignment |
10 | = += … |
Conditional |
20 | ?: |
Coalesce |
30 | ?? |
LogicalOr |
40 | || |
LogicalAnd |
50 | && |
BitwiseOr |
60 | | |
BitwiseXor |
70 | ^ |
BitwiseAnd |
80 | & |
Equality |
90 | == != |
Relational |
100 | < <= > >= is as |
Range |
110 | .. ..= |
Shift |
120 | << >> |
Additive |
130 | + - |
Multiplicative |
140 | * / % |
Power |
141 |
A number between two levels places a symbol between them: precedence(135) binds more strongly than + and less than *.
import System;
public value N
{
public:
i64 X;
new(i64 X);
op +(N a, N b) : N => new N(a.X + b.X);
op *(N a, N b) : N => new N(a.X * b.X);
op ^^(N a, N b) : N precedence(PrecedenceLevel.Power) associativity(Associativity.Right)
{
i64 r = 1;
loop (i64 i = 0..b.X)
r = r * a.X;
return new N(r);
}
op <=>(N a, N b) : i32 precedence(PrecedenceLevel.Relational) associativity(Associativity.None)
=> a.X < b.X ? -1 : a.X > b.X ? 1 : 0;
op <*>(N a, N b) : N precedence(135) => new N(a.X * 100 + b.X);
}
Main()
{
N two = new N(2);
N three = new N(3);
Console.WriteLine((two ^^ three ^^ two).X);
Console.WriteLine(two <=> three);
Console.WriteLine((two + two <*> two * three).X);
}
larva run
512
-1
208
^^is right-associative:2 ^^ 3 ^^ 2is2 ^^ (3 ^^ 2).- With
Associativity.None,a <=> b <=> cis error AN0027: write parentheses. - A symbol has one precedence: every declaration of it, in any type or library, agrees (AN1065). The built-in symbols keep theirs (AN1066).
- When adjacent operator characters can be read several ways, the longest declared symbol wins:
a*-bisa * (-b), anda<-bisa <- bonly if<-is declared. - A program can use a symbol before the place where it is declared, and the symbols a library declares are known to every program that references it.
One-operand operators
An operator with one operand binds more strongly than any binary one and declares no precedence (AN1068).
| Declaration | Used as |
|---|---|
left op #(T a) |
#a |
right op !(T a) |
a! |
op ~~(T a) |
~~a or a~~ |
op -(T a), op !(T a), op ~(T a) |
the built-in prefix forms |
left and right apply only to operators with one operand (AN0025).
public value N
{
public:
i64 X;
new(i64 X);
right op !(N a) : N
{
i64 r = 1;
loop (i64 i = 1..=a.X)
r = r * i;
return new N(r);
}
left op #(N a) : i64 => a.X * 10;
}
N three = new N(3);
(three!).X; // 6
#three; // 30
Conversions
op (Target)(Source s) declares a conversion from Source to Target. It takes one operand (AN0026) and is used with a cast:
op (i64)(Money m) => m.Cents;
op (Money)(i64 cents) => new Money(cents);
i64 cents = (i64)price;
Money back = (Money)99i64;
A declared conversion is always explicit: Money m = 99i64; without a cast is an error.
Generic operators
An operator can have type parameters, written after the symbol. Each one must appear in an operand, so the call can infer it (AN1072):
public value Meters
{
public:
f64 V;
new(f64 V);
op *<T : number>(Meters m, T k) : Meters => new Meters(m.V * (f64)k);
}
(new Meters(2) * 3).V; // 6
Operators as constraints
A type parameter can require an operator: T : op +(T, T) : T, T : left op ++(T) : T, or a conversion T : (i64)T. Inside the generic code the operator can then be used on T. See Generics.
Editar esta página en GitHub Reportar un problema