Basics

Files, namespaces, Main, comments, variables, primitive types, literals, operators, control flow and strings in Antril.

Last updated 10 min read Edit on GitHub

On this page

This page covers what every Antril file uses. Here is a whole program to start with:

AntrilRun
import System;

into namespace Tour
{
	/// Sums the numbers below `limit` that are multiples of 3 or 5.
	SumOfMultiples(i32 limit) : i32
	{
		i32 total = 0;
		loop (i32 n = 1..limit)
		{
			if (n % 3 == 0 || n % 5 == 0)
				total += n;
		}
		return total;
	}

	Main()
	{
		i32 result = SumOfMultiples(10);
		Console.WriteLine($"The sum is {result}");
	}
}
Terminal
larva run
The sum is 23

Files and namespaces

An .ant file is a list of imports followed by declarations: types, functions and constants.

into namespace Name { … } puts declarations into a namespace. The same namespace can be opened in many files and libraries. Declarations outside any into namespace block are in the global namespace.

import brings names into scope for the whole file:

Form What it brings
import System; Every public name of System.
import List, Dictionary from System; Only those names.
import System.Text as T; The namespace under another name: T.JsonValue.
import A, B from D as X, Y; Those names, each with the alias in its position.

A name can always be written in full instead: System.Console.WriteLine("hi").

A type or a function can also name its namespace in its header, relative to where it is written. This is the same as wrapping it in an into namespace block:

AntrilRun
import System;

public class Shape into namespace Geo
{
	public:
		static Sides() : i32 => 4;
}

Area(f64 side) : f64 into namespace Geo => side * side;

Main()
{
	Console.WriteLine(Geo.Area(3) + Geo.Shape.Sides());
}

Main

A program starts at a free function called Main. There is exactly one per program.

Antril
Main()
{
	Console.WriteLine("hello");
}

Main can also be declared with an integer result, Main() : i32: Larva prints that result when the program ends. Main can take numbers from the command line, but not text yet; see Source files.

Comments

Antril
// To the end of the line.

/* Across
   several lines. */

/// A documentation comment: it describes the declaration below it.
/// The editor shows it on hover, and `larva show` prints it.
Area(f64 w, f64 h) : f64 => w * h;

Variables and constants

A variable is declared with its type first. Several variables of one type can share a declaration.

Antril
i32 count = 0;
str name = "Antril";
i32 width = 4, height = 3;

A variable of a value type (numbers, bool, value types) that is not assigned starts at zero.

const declares a constant. Its value is computed when the program compiles, and it can be declared in a namespace, in a type, or inside a body.

AntrilRun
import System;

into namespace Config
{
	const i32 Retries = 3;
	const str Name = "server";
	const str Label = Name + "-" + "main";
	const i64 Big = Int32.MaxValue + 1i64;

	Main()
	{
		const f64 Half = 0.5;
		Console.WriteLine(Label);
		Console.WriteLine(Big);
		Console.WriteLine(Retries * Half);
	}
}
Terminal
larva run
server-main
2147483648
1.5

nameof(x) gives the name of a variable, member, type or function as a constant string: nameof(count) is "count", and nameof(i32) is "Int32".

Primitive types

Type What it is
bool true or false.
i8 i16 i32 i64 i128 i256 Signed integers of 8 to 256 bits.
u8 u16 u32 u64 u128 u256 Unsigned integers of 8 to 256 bits.
f16 f32 f64 f128 f256 IEEE floating-point numbers of 16 to 256 bits.
iptr uptr Integers the size of a pointer.
str Text: a System.String.
any Any value: the root of every class (System.Any). A value stored in any is boxed.
void No value: what a function without a result returns.

Each primitive is a type of the standard library (i32 is System.Int32, f64 is System.Float64), with members such as Int32.MaxValue, Int32.Parse(text) and ToString().

Antril has no separate character type. A character literal like 'A' is its code point, a number: a u16 when nothing else is expected. System.Char has functions on code points, such as Char.IsDigit('7').

Literals

AntrilRun
import System;

Main()
{
	i32 count = 42;
	i64 big = 9_000_000_000;
	u8 small = 255u8;
	f32 ratio = 0.5f32;
	f64 pi = 3.14159;
	i32 mask = 0xFF;
	i32 bits = 0b1010;
	u128 huge = 340282366920938463463374607431768211455u128;
	u16 letter = 'A';
	bool ready = true;
	str name = "Antril\n";
	Console.WriteLine(count + mask + bits);
	Console.WriteLine(big);
	Console.WriteLine(huge);
	Console.WriteLine(letter);
	Console.Write(name);
}
Terminal
larva run
307
9000000000
340282366920938463463374607431768211455
65
Antril
  • An integer literal is an i32, or an i64 if it does not fit. A literal with a decimal point is an f64. Where a type is expected, a literal takes that type.
  • A suffix names the type: 255u8, 1i64, 0.5f32, 3f128.
  • 0x starts a hexadecimal number and 0b a binary one. _ separates digits.
  • Strings use \n, \t, \" and \\ escapes.
  • null is the empty value of a nullable type (see Types).

Conversions

Conversions that cannot lose information are implicit: an integer to a wider one of the same sign, an unsigned integer to a wider signed one, an integer to a float, f32 to f64. Everything else needs a cast:

Antril
i64 wide = 5;              // implicit
i32 narrow = (i32)wide;    // a cast
i8 truncated = (i8)200;    // -56: a cast keeps the low bits
i32 whole = (i32)3.9;      // 3

Operators

Kind Operators
Arithmetic + - * / %, and -x
Comparison == != < <= > >=
Logical && || !
Bitwise & | ^ ~ << >>
Assignment = += -= *= /= %= &= |= ^= <<= >>=
Increment ++ -- (before or after the variable)
Conditional c ? a : b
Null a ?? b (a unless it is null), a?.b (null if a is null)
Types x is T, x is T name, x as T
Ranges a..b (excludes b), a..=b (includes b)

+ joins strings, and turns a number or an object on the other side into text: "n = " + 5 is "n = 5". == on strings compares their content.

Types can declare their own operators; see Functions and generics.

Control flow

if

Antril
if (temperature > 30)
	Console.WriteLine("hot");
else if (temperature > 15)
	Console.WriteLine("mild");
else
	Console.WriteLine("cold");

Braces are needed only for more than one statement.

loop

Antril has one keyword for every kind of loop:

Form What it does
loop (T x in items) { … } Each element of an array, a string or a collection.
loop (condition) { … } While the condition holds. loop (true) runs until a break.
do { … } loop (condition); Runs once, then while the condition holds.
loop (i32 i = 0..10) { … } i from 0 to 9. 0..=10 includes 10.
loop (i32 i = 0; i < 10; i += 2) { … } Start, condition, step.
loop (i32 i = 1) { … } Without end: i starts at 1 and goes up by one each time.

break leaves the loop and continue goes to the next turn.

AntrilRun
import System;

Main()
{
	loop (i32 i = 0..3)
		Console.Write(i);
	Console.WriteLine();

	loop (i32 k = 0; k < 10; k += 3)
		Console.Write(k);
	Console.WriteLine();

	i32 n = 1;
	loop (n < 100)
		n *= 3;
	Console.WriteLine(n);

	do n -= 50; loop (n > 0);
	Console.WriteLine(n);

	loop (i32 c = 1)
	{
		if (c > 3)
			break;
		Console.Write(c);
	}
	Console.WriteLine();

	loop (str word in ["alpha", "beta"])
		Console.WriteLine(word.ToUpper());
}
Terminal
larva run
012
0369
243
-7
123
ALPHA
BETA

switch

switch matches a value against patterns, as a statement or as an expression. _ matches anything.

AntrilRun
import System;

Describe(i32 n) : str => n switch
{
	< 0 => "negative",
	0 => "zero",
	1..10 => "small",
	_ => "large",
};

Main()
{
	i32 count = 2;
	switch (count)
	{
		0 => Console.WriteLine("none");
		1 or 2 => Console.WriteLine("a few");
		_ => Console.WriteLine("many");
	}
	Console.WriteLine(Describe(-3) + ", " + Describe(5) + ", " + Describe(50));
}
Terminal
larva run
a few
negative, small, large

Patterns can be:

  • constants: 0, "abc", Color.Red;
  • comparisons: < 0, >= 90;
  • ranges: 1..10, 1..=9;
  • combinations with and, or and not;
  • types, with an optional name: Circle c;
  • properties: { X: 0, Y: > 1 };
  • positions, for records, tuples and types with Deconstruct: Point(0, var y), (1, _);
  • null.

A when condition after a pattern adds a check: Circle c when c.Radius > 10 => …. The same patterns work after is: if (p is { X: 0 }).

Strings

str is immutable text. Some of its members:

Antril
str s = "  Hello World  ".Trim();
s.Length;                  // 11
s.ToUpper();               // "HELLO WORLD"
s.Substring(6, 5);         // "World"
s.IndexOf("World");        // 6
s.StartsWith("Hell");      // true
s.Replace("World", "you"); // "Hello you"
"a,b,c".Split(',');        // a List<str>
String.Join("-", parts);   // joins a list

An interpolated string starts with $. Each {…} holds an expression, with an optional width after , (negative: aligned left) and a format after ::

AntrilRun
import System;

Main()
{
	f64 price = 3.5;
	i32 quantity = 4;
	Console.WriteLine($"{quantity} x {price} = {price * quantity}");
	Console.WriteLine($"[{quantity,5}] [{quantity,-5}] [{price:F2}]");
}
Terminal
larva run
4 x 3.5 = 14
[    4] [4    ] [3.50]

To build long text piece by piece, use StringBuilder (see the library overview).

Printing

Console.WriteLine writes a value and a new line; Console.Write writes without the new line. Both take every primitive type, strings, and any other value (shown with its ToString()). Console.ReadLine() reads a line, or gives null at the end of the input.

Because a character literal is a number, Console.Write('A') writes 65. Write "A" for text.

Next: Types.

Was this page helpful?

No address is stored; your user name is, if you are signed in.

Esc