Skip to content

Attributes and Directives

Oskar Nordquist edited this page Aug 21, 2020 · 12 revisions

Attributes

  • @(link_name = <string>)
    This attribute can be attached to variable and procedure declarations inside a foreign block. This specifies what the variable/proc is called in the library.
    Example;
foreign foo {
    @(link_name = "bar")
    testbar :: proc(baz : int) ---;
}
  • @(link_prefix = <string>)
    This attribute can be attached to a foreign block to specify a prefix to all names. So if functions are prefixed with ltb_ in the library is you can attach this and not specify that on the procedure on the odin side. Example;
@(link_prefix = "ltb_")
foreign foo {
    testbar :: proc(baz : int) ---; // This now refers to ltb_testbar
}
  • @export or @(export=true/false)

  • @(default_calling_convention = <string>)
    This attribute can be attached to a foreign block to specify the default calling convention for all procedures in the block. Example;

@(default_calling_convention = "std")
foreign kernel32 {
    @(link_name="LoadLibraryA") load_library_a  :: proc(c_str: ^u8) -> Hmodule ---;
}
  • @(deferred_in=<proc>)
  • @(deferred_out=<proc>)
  • @(deferred_in_out=<proc>)
  • @(deferred_none=<proc>)
    These attributes can be attached to a procedure X which will be called at the end of the calling scope for Xs caller.
    deferred_in will receive the same parameters as the called proc. deferred_out will receive the result of the called proc. deferred_in_out will receive both. deferred_none will receive no parameters.
baz :: proc() {
    fmt.println("In baz");
}

@(deferred_none=baz)
bar :: proc() {
    fmt.println("In bar");
}

foo :: proc() {
    fmt.println("Entered foo");
    bar();
    fmt.println("Leaving foo");
}
// Prints:
// Entered foo
// In bar
// Leaving foo
// In baz
  • @(static)
    Can be applied to a variable to have it keep its' state even when going out of scope. Same as a static local variable in C.
test :: proc() -> int {
    @static foo := 0;
    foo += 1;
    return foo;
}

main :: proc() {
    fmt.println(test()); // prints 1
    fmt.println(test()); // prints 2
    fmt.println(test()); // prints 3
}
  • @(thread_local)
    Can be applied to a variable at file scope
@(thread_local) foo: int;
  • @(private)
    Prevents a top level element from being exported with the package. In Odin elements beginning with '_' will not be exported. This attribute allows you to explicitly prevent something from being exported without naming it with an '_'.
package foo

_this_is_private :: 0;
this_is_not :: 1;
@private
this_is_also_private :: 2;
  • @(deprecated=<string>)
    Mark a procedure as deprecated. Running odin build/run/check will print out the message for each usage of the deprecated proc.
@(deprecated="'foo' deprecated, use 'bar' instead")
foo :: proc() {
    ...
}
  • @(builtin)
    Marks builtin procs in Odin's "core:runtime" package. Cannot be used in user code.

Directives

Record Memory Layout

  • #packed
    This tag can be applied to struct. By doing so, the Odin compiler will omit padding and preserve the order of fields in a struct.
  • #raw_union
    This tag can be applied to a struct. Struct's fields will share the same memory space which serves the same functionality as unions in C language. Useful when writing bindings especially.
  • #align
    This tag can be applied to a struct or union. This tag in form #align N specifies the struct's alignment to N bytes.
Foo :: struct #align 4 { 
    b: bool,
}
Bar :: union #align 4 {
    i32,
    u8,
}
  • #no_nil
    This tag can be applied to a union to not allow nil values.
A :: union {int, bool};
B :: union #no_nil {int, bool};
Possible states of A:
{} // nil
{int}
{bool}

Possible states of B:
{int} // default state
{bool}

Control Statements

  • #complete
    This tag can be applied to a switch on an enum to ensure all cases are covered. Notably, it requires all cases to be tested individually, default case does not count.
Foo :: enum {
    A,
    B,
    C,
}

test :: proc() {
    bar := Foo.A;
    // Ok
    #complete switch bar {
    case Foo.A:
    case Foo.B:
    case Foo.C:
    }
    
    // Error
    #complete switch bar {
    case Foo.A:
    case Foo.B:
    case:
    }
}

Procedure Parameters

  • #no_alias This tag can be applied to a procedure parameter that is a pointer. This is a hint to the compiler that this parameter will not alias other parameters. This is equivalent to C's __restrict.
foo :: proc(#no_alias a, b: ^int) {}
  • #caller_location
    This tag is used as a function's parameter value. In the following function signature,
alloc :: inline proc(size: int, alignment: int = DEFAULT_ALIGNMENT, loc := #caller_location) -> rawptr

loc is a variable of type Source_Code_Location (see core/runtime/core.odin) that is automatically filled with the location of the line of code calling the function (in this case, the line of code calling alloc).

  • #c_varag
    Used to interface with vararg functions in foreign procedures.
foreign foo {
    bar :: proc(n: int, #c_vararg args: ..any) ---;
}
  • #require_results
    Ensures procedure return values are acknowledged.
foo :: proc() -> bool #require_results {
    return true;
}

main :: proc() {
    foo(); // won't compile
    _ = foo(); // Ok
}

Expressions

  • #type
    This tag doesn't serve a functional purpose in the compiler, this is for telling someone reading the code that the expression is a type. The main case is for showing that a procedure signature without a body is a type and not just missing its body, for example:
foo :: #type proc(foo : string);

bar :: struct {
    gin : foo;
}
  • #bounds_check
  • #no_bounds_check
    #bounds_check and #no_bounds_check are flags that control Odin's built-in bounds checking of arrays and slices. Any statement, block, or function with one of these flags will have their bounds checking turned on or off, depending on the flag provided. Valid uses of these flags include:
proc_without_bounds_check :: proc() #no_bounds_check {
    #bounds_check {
        #no_bounds_check fmt.println(os.args[1]);
    }
}

Built-in Procedures

  • #assert
    Assert ran at compile time.
  • #defined
    Checks if an identifier is defined.
n: int;
when #defined(n) { fmt.println("true"); }
if #defined(int) { fmt.println("true"); }
when #defined(nonexistent_proc) == false { fmt.println("proc was not defined"); }
  • #file #line #procedure Return the current file path, line number, or procedure name, respectively. Used like a constant value. file_name :: #file;
  • #location
    Returns a runtime.Source_Code_Location (see core/runtime/core.odin). Can be called with no parameters for current location, or with a parameter for the location of the variable/proc declaration
foo :: proc() {};

main :: proc() {
    n: int;
    fmt.println(#location());
    fmt.println(#location(foo));
    fmt.println(#location(n));
  • #load
    Returns a []u8 of file contents at compile time
foo := #load("path/to/file");
bar := #load(#file);
fmt.println(string(foo));
Clone this wiki locally