2.31. Annotations
Annotations are metadata decorators attached to functions, structures, classes, enumerations, and variables. They control compiler behavior — export, initialization, safety, optimization, and macro registration.
An annotation is written in square brackets before the declaration it applies to:
[export]
def main {
print("hello\n")
}
Multiple annotations can be combined with commas:
[export, no_aot]
def main {
print("hello\n")
}
Some annotations accept arguments:
[init(tag="db")]
def init_database {
pass
}
[unused_argument(x, y)]
def foo(x, y : int) {
pass
}
2.31.1. Function Annotations
2.31.1.1. Lifecycle
[export]Marks a function as callable from the host application. The host invokes exported functions by name through the context API:
[export] def main { print("hello\n") }[init]Marks a function to run automatically during context initialization. The function must take no arguments and return
void:[init] def setup { pass }Ordering can be controlled with attributes:
tag— defines a named initialization passbefore— runs before the named passafter— runs after the named pass
All ordering attributes imply late initialization:
[init(tag="db")] def init_database { pass } [init(after="db")] def init_cache { pass }[finalize]Marks a function to run automatically during context shutdown. Same constraints as
[init]— no arguments, no return value:[finalize] def cleanup { pass }Supports a
lateattribute for ordering.[run]Marks a function to run at compile time:
[run] def compile_time_check { print("compiling...\n") }Disabled by the
disable_runoption (see Options).
(see Program Structure for the full initialization lifecycle).
2.31.1.2. Visibility
[private]Makes a function private to the current module. Equivalent to the
privatekeyword beforedef.
2.31.1.3. Safety
[unsafe_deref]Marks a function as allowing unsafe dereferences inside its body:
[unsafe_deref] def read_ptr(p : int?) { return *p }[unsafe_operation]Marks a function as an unsafe operation. Calling it requires an
unsafeblock:[unsafe_operation] def dangerous_thing { pass } unsafe { dangerous_thing() }[unsafe_outside_of_for]Marks a function as unsafe when called outside of a
forloop body.
2.31.1.4. Lint Control
[unused_argument]Suppresses “unused argument” warnings for specific arguments:
[unused_argument(x)] def handler(x : int) { pass }Multiple arguments can be listed:
[unused_argument(x, y)].[nodiscard]Warns if the return value of the function is discarded:
[nodiscard] def compute : int { return 42 } compute() // warning: return value discarded[deprecated]Marks a function as deprecated. Produces a compile-time warning when called:
[deprecated(message="use new_func instead")] def old_func { pass }[no_lint]Disables all lint checks for this function.
[skip_lock_check]Skips array/table lock safety checks inside this function.
[sideeffects]Declares that the function has side effects, even if the compiler cannot detect any. Prevents the optimizer from removing calls to this function.
2.31.1.5. Generics and Contracts
[generic]Marks a function as generic (a template that is instantiated for each unique set of argument types):
[generic] def add(a, b : auto) { return a + b }(see Generic Programming).
[expect_ref]Specialization contract: requires named arguments to be references:
[expect_ref(arr)] def process(var arr : auto) { pass }[expect_dim]Specialization contract: requires named arguments to be fixed-size arrays.
[expect_any_vector]Specialization contract: requires named arguments to be vector template types.
[local_only]Verifies that specific arguments are passed as local constructors. The argument value indicates the expected state —
truemeans the argument must be a literal constructor,falsemeans it must not be:[local_only(data=true)] def process(data : Foo) { pass }
Additional contract annotations are available in daslib/contracts
(see Contract Annotations (daslib) below).
2.31.1.6. Optimization and AOT
[no_aot]Disables AOT (ahead-of-time) compilation for this function.
[no_jit]Disables JIT compilation for this function.
[jit]Requests JIT compilation for this function.
[hybrid]Marks a function as an AOT hybrid — it can call interpreted code from AOT context.
[alias_cmres]Allows aliasing of the copy-on-move return value.
[never_alias_cmres]Prevents aliasing of the copy-on-move return value.
[pinvoke]Marks a function for platform invoke (external function call).
[type_function]Registers the function as usable in type expressions.
2.31.1.7. Macros
[_macro]Marks a function as macro initialization code (runs during macro compilation pass).
[macro_function]Marks a function as existing only in the macro context — excluded from the regular program.
[macro]Defined in
daslib/ast_boost. Like[_macro]but wraps the function body in a module-ready check. Requiresrequire daslib/ast_boost:require daslib/ast_boost [macro] def setup_macros { print("registering macros\n") }[tag_function]Defined in
daslib/ast_boost. Tags a function with string tags for retrieval viafor_each_tag_function:[tag_function(my_tag)] def tagged_func { pass }
2.31.1.8. Markers and Hints
[hint]A dummy annotation that carries key-value arguments for optimization hints. Does not change behavior by itself.
[marker]A generic function marker annotation. Does not change behavior.
2.31.2. Structure and Class Annotations
[cpp_layout]Uses C++ memory layout (matching C++ struct alignment rules):
[cpp_layout] struct CppInterop { x : int y : float }Pass
pod=falseto allow non-POD layouts:[cpp_layout(pod=false)].[safe_when_uninitialized]Marks the struct as safe even when fields are uninitialized (zero-filled memory is a valid state):
[safe_when_uninitialized] struct Vec2 { x : float y : float }[persistent]Makes a structure persistent (survives context reset). All fields must be POD unless
non_pod=trueis specified:[persistent] struct Config { value : int }[no_default_initializer]Suppresses generation of the default constructor for this structure.
[macro_interface]Marks a structure as a macro interface (for the macro system).
[skip_field_lock_check]Skips field-level lock checking on array/table fields of this structure.
[comment]A dummy annotation for attaching comment metadata to a structure.
[tag_structure]Defined in
daslib/ast_boost. Tags a structure with string tags for later retrieval.
2.31.3. Macro Registration Annotations (daslib)
These annotations are defined in daslib/ast_boost and applied to class declarations that
inherit from the appropriate AST base class. They auto-register the class as a macro during
module compilation.
All accept an optional name argument. If omitted, the class name is used.
Annotation |
Base class |
Purpose |
|---|---|---|
|
|
Custom function decorator |
|
|
Custom block decorator |
|
|
Custom struct/class decorator |
|
|
Custom enum decorator |
|
|
Specialization constraint |
|
|
Custom literal/expression reader |
|
|
Custom comment reader |
|
|
Intercepts function-like calls |
|
|
Custom |
|
|
Custom variant type processing |
|
|
Custom for-loop behavior |
|
|
Custom closure capture handling |
|
|
Custom type expression processing |
|
|
Custom simulation node generation |
|
|
Runs during type inference |
|
|
Runs during dirty inference passes |
|
|
Runs during optimization |
|
|
Runs during linting |
|
|
Runs after all modules are compiled |
Example:
require daslib/ast_boost
[function_macro(name="my_decorator")]
class MyDecorator : AstFunctionAnnotation {
def override apply(var func : FunctionPtr; var group : ModuleGroup;
args : AnnotationArgumentList; var errors : das_string) : bool {
print("decorating {func.name}\n")
return true
}
}
(see Macros for details on writing macros).
2.31.4. Contract Annotations (daslib)
These annotations are defined in daslib/contracts and used as specialization constraints
on generic function arguments. Each accepts one or more argument names to constrain.
Requires require daslib/contracts.
Annotation |
Constraint |
|---|---|
|
Argument must be a dynamic array |
|
Argument must be an enum |
|
Argument must be a bitfield |
|
Argument must be a vector template type |
|
Argument must be a struct |
|
Argument must be a numeric type |
|
Argument must be a “workhorse” type (int, float, etc.) |
|
Argument must be a tuple |
|
Argument must be a variant |
|
Argument must be a function type |
|
Argument must be a lambda |
|
Argument must be a reference |
|
Argument must be a pointer |
|
Argument must be a class pointer |
|
Argument must be a value handle type |
Example:
require daslib/contracts
[expect_any_array(arr)]
def first_element(arr : auto) {
return arr[0]
}
2.31.5. Annotation Syntax Details
Annotations can be combined with logical operators for contract composition:
[expect_ref(a) && expect_dim(b)]
def process(var a : auto; b : auto) {
pass
}
Negation is also supported:
[!expect_ref(a)]
def no_ref(a : auto) {
pass
}
Annotations on struct/class fields appear before the field name in the @ metadata syntax:
class Foo {
@big
@min = 13
@max = 42
value : int
}
These @ decorators attach metadata to the field. They are accessible via typeinfo and
at compile time in macros.