How to Use Intrinsic Functions in Sway Contracts: A Complete Guide
Intrinsic functions in Sway contracts provide low-level, compiler-provided operations that map directly to Fuel VM instructions, accessible either through safe standard library wrappers or directly via double-underscore prefixes for advanced use cases.
The FuelLabs/sway repository exposes these compiler intrinsics through a two-layer architecture that balances safety with zero-overhead performance. Understanding how to leverage intrinsic functions in Sway contracts allows developers to query type information, perform raw memory operations, and access VM-specific features that are unavailable through standard language constructs.
What Are Intrinsic Functions in Sway?
Sway provides two distinct layers for low-level, compiler-provided operations called intrinsics:
| Layer | Purpose | Location |
|---|---|---|
| Compiler intrinsics | Direct, unchecked access to VM-level features via special functions the compiler replaces with bytecode instructions | Compiler internals (prefixed with __) |
| Std-lib wrappers | Safe, publicly exported functions that forward to compiler intrinsics with type safety | sway-lib-std/src/intrinsics.sw |
Compiler Intrinsics: The __ Prefix
Compiler intrinsics are special functions prefixed with double underscores (__) that the Sway compiler replaces directly with Fuel VM instructions. These include operations like __size_of, __addr_of, __gtf, __eq, __slice, and __dbg. Because they bypass standard safety checks, direct intrinsics are not part of the public API and may change without semantic versioning guarantees.
Standard Library Wrappers
The standard library provides safe wrappers in std::intrinsics that expose intrinsic functionality with proper type constraints. These wrappers live in sway-lib-std/src/intrinsics.sw and include functions like size_of::<T>(), is_reference_type::<T>(), and eq(). Contract authors should use these wrappers for production code to ensure future compatibility and type safety.
Architecture and Implementation
The Sway compiler processes intrinsic functions through a well-defined pipeline from parsing to code generation.
Parsing and AST Definitions
Intrinsic signatures are defined at the parser level in sway-ast/src/intrinsics.rs. This module establishes the recognized intrinsic names and their expected argument patterns, allowing the parser to identify calls like __size_of::<T>() during the initial syntax analysis phase.
Semantic Analysis
Type checking and validation occur in sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rs. This module enforces type constraints—for example, ensuring __eq<T> only accepts primitive numeric or boolean types—and resolves generic parameters before code generation.
Code Generation
During the compilation phase, the compiler emits Fuel VM instructions directly for intrinsic calls. The type representation layer in sway-core/src/language/ty/expression/intrinsic_function.rs maintains the low-level mapping between high-level intrinsic calls and their corresponding VM bytecode, ensuring zero-overhead execution.
Practical Examples of Intrinsic Functions
Getting Type Sizes with size_of
The size_of wrapper returns the size of any type in bytes, useful for memory allocation and buffer calculations:
use std::intrinsics::size_of;
pub struct Point {
x: u64,
y: u64,
}
fn main() {
// Primitive types
assert(size_of::<u64>() == 8);
// User-defined structs
assert(size_of::<Point>() == 16);
}
Implementation reference: size_of wrapper in sway-lib-std/src/intrinsics.sw (lines 24-53).
Detecting Reference Types
Use is_reference_type to determine if a type is passed by reference at runtime:
use std::intrinsics::is_reference_type;
fn main() {
// Primitive values return false
assert(!is_reference_type::<u64>());
// References return true
assert(is_reference_type::<&u64>());
}
Implementation reference: is_reference_type wrapper in sway-lib-std/src/intrinsics.sw (lines 4-22).
Direct Memory Access with __addr_of
For advanced scenarios requiring raw pointers, use the direct compiler intrinsic __addr_of:
fn main() {
let x = 42;
// Returns a raw pointer to the value
let ptr = __addr_of::<u64>(x);
// Pointer can be used with arithmetic intrinsics like __ptr_add
}
Documentation reference: __addr_of specification in docs/book/src/reference/compiler_intrinsics.md.
Equality Comparisons
The eq wrapper provides type-safe equality checks backed by the __eq intrinsic:
use std::intrinsics::eq;
fn main() {
let a: u64 = 10;
let b: u64 = 10;
assert(eq(a, b)); // Calls __eq under the hood
}
Implementation note: The eq wrapper forwards to __eq, defined in the compiler at sway-core/src/language/ty/expression/intrinsic_function.rs.
When to Use Direct Intrinsics vs Wrappers
Use standard library wrappers for all production contract development. The std::intrinsics module provides type safety, semantic versioning guarantees, and cleaner error messages.
Use direct compiler intrinsics only when:
- Building advanced libraries that require zero-overhead calls and accept the unsafe nature of double-underscore names
- Debugging compiler behavior with intrinsics like
__dbg - Accessing intrinsics not yet exposed in the standard library
Direct intrinsics are not part of the public API and may change without a semver bump. The compiler enforces type constraints at compile time—for example, __eq<T> only works with primitive numeric or boolean types, while __addr_of<T> works for any value.
Summary
- Intrinsic functions provide direct access to Fuel VM instructions through compiler-built-in operations.
- Two-layer architecture: Compiler intrinsics (
__prefix) offer raw VM access, whilestd::intrinsicswrappers provide safe, versioned APIs. - Key files:
sway-lib-std/src/intrinsics.swcontains wrappers;docs/book/src/reference/compiler_intrinsics.mddocuments raw intrinsics;sway-core/src/semantic_analysis/ast_node/expression/intrinsic_function.rshandles type checking. - Common use cases: Type size inspection (
size_of), reference type detection (is_reference_type), raw memory access (__addr_of), and equality comparisons (eq). - Safety recommendation: Use
std::intrinsicswrappers for production code; reserve direct__intrinsics for advanced library development or debugging.
Frequently Asked Questions
What is the difference between __size_of and size_of in Sway?
__size_of is a compiler intrinsic that maps directly to a Fuel VM instruction, while size_of is a safe wrapper function defined in sway-lib-std/src/intrinsics.sw that calls __size_of internally. You should use size_of in production code because it is part of the stable public API, whereas __size_of is an implementation detail that may change without notice.
Are intrinsic functions in Sway safe to use?
Standard library intrinsic wrappers like size_of, eq, and is_reference_type are completely safe and type-checked by the compiler. However, direct compiler intrinsics prefixed with __ bypass certain safety guarantees—for example, __slice and __elem_at do not perform bounds checks, and __addr_of exposes raw pointers. Use direct intrinsics only when building low-level libraries or debugging.
How do I import intrinsic functions in a Sway contract?
Import the safe wrappers from the standard library using use std::intrinsics::* for all available functions, or specify individual imports like use std::intrinsics::{size_of, is_reference_type}. These wrappers are defined in sway-lib-std/src/intrinsics.sw and provide type-safe access to compiler intrinsics without requiring the __ prefix.
Can I create custom intrinsic functions in Sway?
No, intrinsic functions are built into the Sway compiler and cannot be defined by users. They represent special operations that the compiler maps directly to Fuel VM bytecode instructions. However, you can create wrapper functions around existing intrinsics to provide domain-specific APIs, similar to how the standard library wraps __size_of with size_of.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →