Intrinsics
An intrinsic is a value or function whose meaning the compiler supplies directly — there is no Rux body to write, because the compiler knows the answer. The build context (#target, #build, #compiler, #source, #config) is built entirely from intrinsics, and a handful of standard-library routines are intrinsics too.
Most code simply imports intrinsics from the standard Rux package and uses them. Declaring one is reserved for the standard library and advanced interop; the intrinsic keyword exists so those declarations can name what the compiler must provide.
Declaring an Intrinsic
The intrinsic keyword prefixes a declaration that has no body. It comes in two shapes.
An intrinsic value is a #-prefixed name with an explicit type. The type names which intrinsic the compiler binds:
intrinsic #target: Target; // the compiler supplies a Target value
An intrinsic function is an ordinary signature the compiler implements:
intrinsic func Assert(condition: bool, message: Slice<char8> = "assertion failed");
Giving either form a body is an error — the compiler provides it.
Namespaced Intrinsics
An intrinsic method is declared inside an extend block, which namespaces it under the type. This is how #target.HasFeature(...) and #config.Get(...) are defined:
extend Target {
intrinsic func HasFeature(feature: TargetFeature) -> bool;
}
extend Config {
intrinsic func Get(name: Slice<char8>) -> Slice<char8>;
intrinsic func Has(name: Slice<char8>) -> bool;
}
Importing Intrinsics
Because the build-context intrinsics live in the Rux package, a file that uses one must import it by its #-prefixed name — the same as any other item:
import Core::{ #target, #source };
A name used in a when condition must be imported this way; the compiler reports an unknown identifier otherwise. An intrinsic declaration in the current file brings the name into scope locally with the same effect.
Source-Location Intrinsics
The #source intrinsic exposes the current location — #source.file, #source.line, #source.function, and friends. Used as a default argument it expands at the call site, letting a function capture where it was called from. This is the mechanism behind Assert and Panic, and it replaces the earlier standalone #file / #line constants.
import Core::{ #source };
import Io::Print;
func Require(ok: bool, file: Slice<char8> = #source.file, line: uint32 = #source.line) {
if !ok {
Print("requirement failed at {}:{}\n", file, line);
Panic("requirement failed");
}
}
See Also
- Build Context — the intrinsics
#target,#build,#compiler,#source, and#config - Conditional Compilation — where imported intrinsics are most used
- Constants — declaring your own compile-time values
- Function Declaration — default arguments, which source-location intrinsics rely on
Build Context
The build context is a set of five intrinsics the compiler fills in for each build. Every one is declared by the standard Rux package, so you import the ones you use:
Overview
An attribute attaches metadata to a declaration, written as an #Name(...) attribute call on the line before the item it annotates. Attributes instruct the compiler — to link a foreign library, fix a calling convention, or flag a function at its call sites — without changing the declaration's own code.