The ante keyword is used for all things compile-time in Ante. It is a modifier that can be applied to function declarations, variable declarations, type declarations, and arbitrary expressions. The most common use however, is the declaration of compile-time functions. Note that when declaring such a function (an “ante function”), you do not need to use the ante keyword to call the function, only to declare it. ante fun make_private: Type t = import Ante.
Ante provides two forms of loops: while and for. While While loops are the most basic form of loop, they continue executing their body while the given condition remains true. The syntax is as follows: while <expr> do <expr> The first expression is the loop condition and must evaluate to a bool. The second expression is the body to loop over, and is usually a block. While loops are often used when you are unsure precisely how many times you should loop.
Pattern matching is a powerful tool that compares a value against a several patterns until it finds one that matches. These patterns can range from simple literal values to a complex assortment and combination of other patterns, most of which are covered below. Perhaps most importantly, pattern Matches with are completeness checked, so all possibilities for a given value must be covered. For example, a match against an integer x with a single pattern 0 (the equivalent of if x = 0) is rejected as it does not have a case for when x !
In Ante if is an expression that can conditionally do one thing if its condition is true and otherwise do something else if its condition is false. For example, if you wanted to print “good afternoon” only if the time on the clock is after 12:00 then you could write: if Time.is_after "12:00" then print "good afternoon" An else branch can also be added to do something if the given condition was false.
Ante is an indentation sensitive language. The beginning and end of blocks are marked by an increase in indentation and a decrease in indentation respectively and the indentation before a line of non-comment code is called significant whitespace. Ante’s policy on significant whitespace is to keep it as intuitive as possible by preventing inconsistensies that would otherwise hamper code readability. For example, indentations of a single space in size are considered to be a mistake and will trigger an appropriate error message.
Traits are a way to express the desired behaviour of a type without stating which type you need specifically. A function taking in a parameter with a trait type can take any argument whose type implements that trait. Traits are generally advantageous over type variables because they provide better error messages. For example, if a given type that does not implement a print function is passed to a function expecting a Printable variable the compiler will issue an error saying that the provided argument must implement Printable and list the functions required to do so.
Modules provide a method to separate implementation from interface. They may contain types, traits, functions, and global variables, although the latter is discouraged. Before importing a module, the modules names can be accessed through indexing the hierarchy of modules with the . operator. For example, accessing a function f in the module SubModule which itself is within the module Module can be done with Module.SubModule.f. This is the primary method to access other modules, with the one exception that the current module has all of its names already imported, thus if the current module is the SubModule above then the function can be accessed with just f.
As the “compile-time” language Ante naturally needs a mechanism for interacting with the compiler and other compile-time constructs. Of course, you can use the ante modifier or any of the builtin compile-time functions in the Ante module but to properly leverage the full power of Ante it is necessary to learn about compiler directives. In Ante, compiler directives are essentially user-defined modifiers. Just like modifiers, compiler-directives can be used to modify variable declarations, function declarations, or even arbitrary expressions.
Depending on the semantics of the modifier, modifiers appear before any function declaration, variable declaration, type declaration, type, or arbitrary expression. All modifiers can be used before a block to apply the modifier to the entire block. Visibility Modifiers The visibility modifiers control how “visible” declarations are to external modules. There are three visibility modifiers in Ante: pub, pri, and pro, short for public, private, and protected respectively. Something that is public is visible to all modules, something that is private is visible to only the current module, and something that is protected is visible only to modules that extend the current module.
Variables come in two main varieties: mutable and immutable. Immutable variables cannot be changed once set although they can shadow other variables of the same name. Mutable variables on the other hand can be changed, or “assigned”. Following an assignment the mutable variable then refers to the newly assigned value and the old value, unless it is also stored elsewhere, is lost. Both forms of declaration infer the type of the variable from the type of the expression so it is never necessary to write out the type of the variable.