Language Reference
MathViz is a statically-typed language with type inference, designed for mathematical computation and animation. It compiles to optimized Python with automatic NumPy conversions, Numba JIT injection, and runtime set operations. This reference covers every language construct with real compiled output from the MathViz compiler.
1. Variables & Types
MathViz provides three variable declaration keywords: let for mutable variables,
const for compile-time constants, and optional type annotations for explicit typing.
The compiler infers types when annotations are omitted.
let - Mutable Variables
let x = 42 // Type inferred as Int
let y: Float = 3.14 // Explicit type annotation
let name = "MathViz" // String
x = 100 // Variables can be reassigned
x = 42
y: float = 3.14
name = 'MathViz'
x = 100
const - Compile-Time Constants
const PI = 3.14159265358979
const MAX_SIZE = 1024
const TAU = 2.0 * PI
# Constants are inlined at compile time
PI = 3.14159265358979
MAX_SIZE = 1024
TAU = (2.0 * 3.14159265358979)
Type Annotations
MathViz supports a rich type system. Type annotations are optional thanks to inference, but recommended for function signatures.
fn typed_function(x: Int, y: Float) -> Float {
return x * y + 1.0
}
fn with_collections(items: List[Int]) -> Int {
let total = 0
for item in items {
total = total + item
}
return total
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba
@njit(cache=True)
def typed_function(x: int, y: float) -> float:
return ((x * y) + 1.0)
@njit(cache=True)
def with_collections(items: list[int]) -> int:
total = 0
for item in items:
total = (total + item)
return total
All Supported Types
| MathViz Type | Python Type | Description |
|---|---|---|
Int | int | Integer numbers |
Float | float | Floating-point numbers |
Bool | bool | Boolean values (true/false) |
String | str | Text strings |
None | None | Absence of value |
List[T] | list[T] | Ordered, mutable collection |
Set[T] | set[T] | Unordered, unique elements |
Dict[K, V] | dict[K, V] | Key-value mapping |
Tuple[T...] | tuple[T...] | Fixed-size, mixed types |
Vec[T] | np.ndarray | NumPy vector |
Mat[T] | np.ndarray | NumPy matrix |
Array[T] | np.ndarray | NumPy N-dimensional array |
Optional[T] | T | None | May or may not have a value |
Result[T, E] | T (with exceptions) | Success or error |
2. Functions
Functions are declared with fn. Use pub fn to make them
public (exportable from modules). The compiler automatically adds @njit(cache=True)
to pure numeric functions.
Basic Functions & Return Types
fn typed_function(x: Int, y: Float) -> Float {
return x * y + 1.0
}
fn with_collections(items: List[Int]) -> Int {
let total = 0
for item in items {
total = total + item
}
return total
}
@njit(cache=True)
def typed_function(x: int, y: float) -> float:
return ((x * y) + 1.0)
@njit(cache=True)
def with_collections(items: list[int]) -> int:
total = 0
for item in items:
total = (total + item)
return total
Public Functions (Modules)
// math_utils.mviz - Module file
pub fn factorial(n) {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
pub fn fibonacci(n) {
if n <= 1 {
return n
}
return fibonacci(n - 1) + fibonacci(n - 2)
}
fn private_helper() {
return 42
}
@njit(cache=True)
def factorial(n):
if (n <= 1):
return 1
return (n * factorial((n - 1)))
@njit(cache=True)
def fibonacci(n):
if (n <= 1):
return n
return (fibonacci((n - 1)) + fibonacci((n - 2)))
@njit(cache=True)
def private_helper():
return 42
The pub keyword controls visibility in the module system. Private functions
(fn) cannot be imported from other modules. Both public and private functions
receive JIT optimization when eligible.
Lambda Expressions
// Pipe-lambda syntax (Rust-like)
let double = |x| x * 2
let add = |a, b| a + b
// Used with iterators
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
let doubled = numbers.map(|x| x * 2)
let big = numbers.filter(|x| x > 5)
let total = numbers.reduce(0, |acc, x| acc + x)
double = lambda x: (x * 2)
add = lambda a, b: (a + b)
# Iterator methods use runtime library
numbers = np.array([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], dtype=np.int64)
doubled = iter_map(numbers, lambda x: (x * 2))
big = iter_filter(numbers, lambda x: (x > 5))
total = iter_reduce(numbers, 0, lambda acc, x: (acc + x))
3. Control Flow
if / elif / else
pub fn factorial(n) {
if n <= 1 {
return 1
}
return n * factorial(n - 1)
}
pub fn gcd(a, b) {
if b == 0 {
return a
}
return gcd(b, a % b)
}
@njit(cache=True)
def factorial(n):
if (n <= 1):
return 1
return (n * factorial((n - 1)))
@njit(cache=True)
def gcd(a, b):
if (b == 0):
return a
return gcd(b, (a % b))
for Loops & Ranges
MathViz supports 0..n (exclusive) and 0..=n (inclusive) range syntax.
Ranges compile to Python's range().
// Pure numeric loop - gets @njit
fn compute_sum(n: Int) -> Float {
let total = 0.0
for i in 0..n {
total = total + sqrt(i * 1.0)
}
return total
}
@njit(cache=True)
def compute_sum(n: int) -> float:
total = 0.0
for i in range(0, n):
total = (total + np.sqrt((i * 1.0)))
return total
while Loops
let count = 0
while count < 10 {
print(count)
count += 1
}
break and continue
for i in 0..100 {
if i == 5 {
continue // Skip to next iteration
}
if i == 10 {
break // Exit loop
}
print(i)
}
4. Pattern Matching
MathViz supports match expressions that compile to chained ternary
expressions in Python. This provides concise pattern-based branching.
fn classify(x: Int) -> String {
let result = match x {
0 -> "zero"
1 -> "one"
_ -> "other"
}
return result
}
def classify(x: int) -> str:
result = (lambda _match_subj: (
'zero' if _match_subj == 0
else ('one' if _match_subj == 1
else 'other')
))(x)
return result
The compiler transforms match into an immediately-invoked lambda with
chained ternary expressions. The wildcard _ becomes the final else clause.
The subject is captured in _match_subj to avoid re-evaluation.
Match with Enums
fn describe_number(n: Int) -> String {
match n {
0 -> "zero"
1 -> "one"
n where n < 0 -> "negative"
n where n > 100 -> "large"
_ -> "other"
}
}
fn calculate_area(shape: Shape) -> Float {
match shape {
Shape::Circle(r) -> PI * r ^ 2
Shape::Rectangle(w, h) -> w * h
Shape::Point -> 0.0
}
}
5. Comprehensions
MathViz supports list, set, and dict comprehensions with optional filters.
Ranges in comprehensions compile to range(), and the ^
operator compiles to **.
fn list_ops() {
// Basic list comprehension
let squares = [x^2 for x in 0..10]
// With filter
let evens = [x for x in 0..20 if x % 2 == 0]
// Nested comprehension
let nested = [x * y for x in 1..4 for y in 1..4]
return squares
}
fn set_comp() {
// Set comprehension (unique values)
let unique_squares = {x^2 for x in -5..6}
return unique_squares
}
@njit(cache=True)
def list_ops():
squares = [(x ** 2) for x in range(0, 10)]
evens = [x for x in range(0, 20) if ((x % 2) == 0)]
nested = [(x * y) for x in range(1, 4) for y in range(1, 4)]
return squares
@njit(cache=True)
def set_comp():
unique_squares = {(x ** 2) for x in range((-5), 6)}
return unique_squares
x^2 becomes (x ** 2), ranges 0..10 become
range(0, 10), and negative bounds like -5..6 become
range((-5), 6). Dict comprehensions use {k: v for ...} syntax.
6. Operators
Arithmetic Operators
| MathViz | Python Output | Description | Example |
|---|---|---|---|
+ | + | Addition | 5 + 3 |
- | - | Subtraction | 5 - 3 |
* | * | Multiplication | 5 * 3 |
/ | / | Division | 5 / 3 |
// | // | Floor division | 5 // 3 |
% | % | Modulo | 5 % 3 |
^ | ** | Exponentiation | 2 ^ 10 → (2 ** 10) |
** | ** | Exponentiation (alt) | 2 ** 10 |
Comparison Operators
| MathViz | Python Output | Description |
|---|---|---|
== | == | Equal to |
!= | != | Not equal to |
< | < | Less than |
<= | <= | Less than or equal |
> | > | Greater than |
>= | >= | Greater than or equal |
Logical Operators
fn constant_folding_demo() {
let a = 2 + 3
let b = 10 * 4
let c = "hello" + " world"
let d = true and false
let e = 2^10
return a + b
}
def constant_folding_demo():
a = (2 + 3)
b = (10 * 4)
c = ('hello' + ' world')
d = (True and False)
e = (2 ** 10)
return (a + b)
| MathViz | Python Output | Description |
|---|---|---|
and | and | Logical AND |
or | or | Logical OR |
not | not | Logical NOT |
true | True | Boolean true |
false | False | Boolean false |
7. Unicode Math Operators
MathViz natively supports Unicode mathematical symbols. The compiler translates
them into function calls from the mathviz.runtime library or literal values.
| Unicode | Name | MathViz Usage | Compiled Python |
|---|---|---|---|
∈ | Element of | 3 ∈ A | is_element(3, A) |
∉ | Not element of | 10 ∉ A | is_not_element(10, A) |
⊆ | Subset or equal | {1, 2} ⊆ A | is_subset({1, 2}, A) |
⊇ | Superset or equal | A ⊇ {1, 2} | is_superset(A, {1, 2}) |
∪ | Union | A ∪ B | set_union(A, B) |
∩ | Intersection | A ∩ B | set_intersection(A, B) |
∖ | Set difference | A ∖ B | set_difference(A, B) |
π | Pi | let x = π | x = 3.141592653589793 |
∞ | Infinity | let x = ∞ | x = float('inf') |
√ | Square root | √(x) | np.sqrt(x) |
≈ | Approximately equal | a ≈ b | np.isclose(a, b) |
≠ | Not equal | a ≠ b | a != b |
≤ | Less or equal | a ≤ b | a <= b |
≥ | Greater or equal | a ≥ b | a >= b |
∑ | Summation | ∑(list) | np.sum(list) |
∏ | Product | ∏(list) | np.prod(list) |
8. Set Operations
MathViz provides first-class set operations using Unicode symbols. The compiler
imports helper functions from mathviz.runtime and replaces each
operator with the corresponding function call.
fn set_operations() {
let a = {1, 2, 3, 4, 5}
let b = {3, 4, 5, 6, 7}
let u = a ∪ b // Union
let inter = a ∩ b // Intersection
let diff = a ∖ b // Difference
let is_sub = {1, 2} ⊆ a // Subset check
let is_in = 3 ∈ a // Membership
let not_in = 10 ∉ a // Non-membership
let pi_val = π // Mathematical Pi
let inf_val = ∞ // Infinity
return u
}
from mathviz.runtime import (
set_union,
set_intersection,
set_difference,
is_subset,
is_superset,
is_element,
is_not_element,
)
def set_operations():
a = {1, 2, 3, 4, 5}
b = {3, 4, 5, 6, 7}
u = set_union(a, b)
inter = set_intersection(a, b)
diff = set_difference(a, b)
is_sub = is_subset({1, 2}, a)
is_in = is_element(3, a)
not_in = is_not_element(10, a)
pi_val = 3.141592653589793
inf_val = float('inf')
return u
When the compiler detects Unicode set operators, it automatically adds the
from mathviz.runtime import ... block at the top of the generated file.
Functions that use sets do not receive @njit because
the runtime helpers are pure Python.
9. NumPy Auto-Conversions
The MathViz compiler automatically converts mathematical function calls to their
NumPy equivalents. When any NumPy function is detected, the compiler adds
import numpy as np and the Numba JIT imports to the generated file.
Math Functions
fn math_operations() {
let x = 2.0
let y = sqrt(x)
let z = sin(x) + cos(x)
let w = exp(x) + log(x)
let t = floor(3.7) + ceil(3.2)
return y + z + w + t
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba
@njit(cache=True)
def math_operations():
x = 2.0
y = np.sqrt(x)
z = (np.sin(x) + np.cos(x))
w = (np.exp(x) + np.log(x))
t = (np.floor(3.7) + np.ceil(3.2))
return (((y + z) + w) + t)
Array Creation
fn array_operations() {
let a = zeros(10)
let b = ones(10)
let c = linspace(0, 1, 100)
let d = arange(0, 10, 1)
let e = eye(3)
return a
}
@njit(cache=True)
def array_operations():
a = np.zeros(10)
b = np.ones(10)
c = np.linspace(0, 1, 100)
d = np.arange(0, 10, 1)
e = np.eye(3)
return a
Complete NumPy Conversion Table
Below is the complete list of MathViz functions that auto-convert to NumPy.
Write plain function names in MathViz; the compiler handles the np. prefix.
| Category | MathViz | Compiled Python |
|---|---|---|
| Trigonometry | sin(x) | np.sin(x) |
cos(x) | np.cos(x) | |
tan(x) | np.tan(x) | |
asin(x) | np.arcsin(x) | |
acos(x) | np.arccos(x) | |
atan(x) | np.arctan(x) | |
| Exponential | exp(x) | np.exp(x) |
log(x) | np.log(x) | |
log2(x) | np.log2(x) | |
log10(x) | np.log10(x) | |
| Rounding | floor(x) | np.floor(x) |
ceil(x) | np.ceil(x) | |
round(x) | np.round(x) | |
| Powers | sqrt(x) | np.sqrt(x) |
abs(x) | np.abs(x) | |
| Array Creation | zeros(n) | np.zeros(n) |
ones(n) | np.ones(n) | |
linspace(a, b, n) | np.linspace(a, b, n) | |
arange(a, b, s) | np.arange(a, b, s) | |
eye(n) | np.eye(n) | |
| Statistics | mean(x) | np.mean(x) |
std(x) | np.std(x) | |
var(x) | np.var(x) | |
max(x) | np.max(x) | |
min(x) | np.min(x) | |
| Linear Algebra | matmul(a, b) | np.matmul(a, b) |
dot(a, b) | np.dot(a, b) | |
cross(a, b) | np.cross(a, b) | |
transpose(a) | np.transpose(a) | |
det(a) | np.linalg.det(a) |
10. Matrix & Vector Operations
MathViz supports matrix and vector operations that compile to NumPy. List literals
used as matrices are converted to np.array with appropriate dtypes.
fn matrix_ops() {
let a = [[1, 2], [3, 4]]
let b = [[5, 6], [7, 8]]
let c = matmul(a, b)
let d = transpose(a)
let e = dot([1, 2, 3], [4, 5, 6])
return c
}
@njit(cache=True)
def matrix_ops():
a = [np.array([1, 2], dtype=np.int64),
np.array([3, 4], dtype=np.int64)]
b = [np.array([5, 6], dtype=np.int64),
np.array([7, 8], dtype=np.int64)]
c = np.matmul(a, b)
d = np.transpose(a)
e = np.dot(
np.array([1, 2, 3], dtype=np.int64),
np.array([4, 5, 6], dtype=np.int64)
)
return c
Integer lists compile to np.array([...], dtype=np.int64) while
float lists compile to np.array([...], dtype=np.float64). The compiler
infers the dtype from the literal values in the list.
Statistics on Arrays
fn stats() {
let data = [1, 2, 3, 4, 5]
let m = mean(data)
let s = std(data)
let v = var(data)
let mx = max(data)
let mn = min(data)
return m
}
@njit(cache=True)
def stats():
data = np.array([1, 2, 3, 4, 5], dtype=np.int64)
m = np.mean(data)
s = np.std(data)
v = np.var(data)
mx = np.max(data)
mn = np.min(data)
return m
11. Iterator Methods
MathViz provides Rust-inspired iterator methods that chain on collections.
These compile to function calls from mathviz.runtime.iterators,
a comprehensive functional programming toolkit.
fn iterator_demo() {
let numbers = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
// Transform
let doubled = numbers.map(|x| x * 2)
// Filter
let big = numbers.filter(|x| x > 5)
// Reduce with initial value
let total = numbers.reduce(0, |acc, x| acc + x)
return doubled
}
from mathviz.runtime.iterators import (
# Transformation
iter_map, iter_filter, iter_reduce, iter_fold,
iter_flat_map, iter_flatten,
# Access
iter_first, iter_last, iter_nth, iter_find,
iter_position,
# Predicate
iter_any, iter_all, iter_none, iter_count,
iter_count_if,
# Numeric
iter_sum, iter_product, iter_min, iter_max,
iter_average, iter_min_by, iter_max_by,
# Slicing
iter_take, iter_skip, iter_take_while,
iter_skip_while,
# Ordering
iter_sorted, iter_sorted_by, iter_sorted_by_desc,
iter_reversed,
# Combination
iter_zip, iter_enumerate, iter_chain, iter_chunk,
iter_unique,
# Collection
iter_collect_list, iter_collect_set,
iter_collect_dict, iter_join, iter_group_by,
iter_partition,
# Dict-specific
dict_keys, dict_values, dict_items,
dict_map_values, dict_filter_keys,
dict_filter_values,
)
@njit(cache=True)
def iterator_demo():
numbers = np.array(
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10],
dtype=np.int64
)
doubled = iter_map(numbers, lambda x: (x * 2))
big = iter_filter(numbers, lambda x: (x > 5))
total = iter_reduce(
numbers, 0, lambda acc, x: (acc + x)
)
return doubled
Complete Iterator Method Table
| Category | MathViz Method | Compiled Function | Description |
|---|---|---|---|
| Transform | .map(|x| expr) | iter_map(seq, fn) | Apply function to each element |
.filter(|x| cond) | iter_filter(seq, fn) | Keep elements matching predicate | |
.flat_map(|x| expr) | iter_flat_map(seq, fn) | Map then flatten | |
.flatten() | iter_flatten(seq) | Flatten nested lists | |
| Reduce | .reduce(init, |a,x| expr) | iter_reduce(seq, init, fn) | Reduce to single value |
.fold(init, |a,x| expr) | iter_fold(seq, init, fn) | Same as reduce (alias) | |
.sum() | iter_sum(seq) | Sum all elements | |
| Access | .first() | iter_first(seq) | First element |
.last() | iter_last(seq) | Last element | |
.nth(n) | iter_nth(seq, n) | Nth element | |
.find(|x| cond) | iter_find(seq, fn) | First matching element | |
.position(|x| cond) | iter_position(seq, fn) | Index of first match | |
| Predicate | .any(|x| cond) | iter_any(seq, fn) | Any element matches? |
.all(|x| cond) | iter_all(seq, fn) | All elements match? | |
.count() | iter_count(seq) | Count elements | |
| Slice | .take(n) | iter_take(seq, n) | First n elements |
.skip(n) | iter_skip(seq, n) | Skip first n elements | |
.take_while(|x| cond) | iter_take_while(seq, fn) | Take while predicate holds | |
.skip_while(|x| cond) | iter_skip_while(seq, fn) | Skip while predicate holds | |
| Combine | .zip(other) | iter_zip(seq, other) | Pair elements from two lists |
.enumerate() | iter_enumerate(seq) | Add index to each element | |
.chain(other) | iter_chain(seq, other) | Concatenate two sequences | |
.chunk(n) | iter_chunk(seq, n) | Split into n-sized groups | |
.unique() | iter_unique(seq) | Remove duplicates | |
| Order | .sorted() | iter_sorted(seq) | Sort ascending |
.sorted_by(|x| key) | iter_sorted_by(seq, fn) | Sort by key function | |
.reversed() | iter_reversed(seq) | Reverse order |
12. Automatic JIT Optimization
The MathViz compiler automatically injects Numba @njit(cache=True)
decorators on functions that are eligible for JIT compilation. This happens
transparently -- you write plain MathViz code, and the compiler optimizes it.
Pure Numeric Functions Get @njit
// Pure numeric function - auto @njit
fn compute_sum(n: Int) -> Float {
let total = 0.0
for i in 0..n {
total = total + sqrt(i * 1.0)
}
return total
}
// Math-heavy function - auto @njit
fn transcendental(x: Float) -> Float {
return sin(x) * cos(x) + exp(-x) * log(x + 1)
}
// Has print() - still gets @njit
fn display_result(x: Float) {
print(x)
}
import numpy as np
from numba import jit, njit, vectorize, prange
import numba
@njit(cache=True)
def compute_sum(n: int) -> float:
total = 0.0
for i in range(0, n):
total = (total + np.sqrt((i * 1.0)))
return total
@njit(cache=True)
def transcendental(x: float) -> float:
return ((np.sin(x) * np.cos(x))
+ (np.exp((-x)) * np.log((x + 1))))
@njit(cache=True)
def display_result(x: float):
print(x, end='')
JIT Eligibility Rules
| Condition | JIT Applied? | Explanation |
|---|---|---|
| Pure numeric (int, float, numpy) | Yes - @njit(cache=True) | No Python objects involved |
| Uses NumPy functions (sin, sqrt...) | Yes - @njit(cache=True) | NumPy is Numba-compatible |
| Uses print() | Yes - @njit(cache=True) | Numba supports basic print |
| Uses set operations (Unicode) | No | Runtime helpers are pure Python |
| Uses string concatenation | No | String ops not Numba-compatible |
| Scene methods (Manim) | No | Manim objects not Numba-compatible |
When any function in a file uses numeric types, the compiler adds the full Numba
import block (from numba import jit, njit, vectorize, prange) even
if not all imports are used. This is by design for consistency.
13. Automatic Vectorization
When the compiler detects loop patterns operating on numeric arrays, it can
auto-vectorize them using NumPy array operations. Combined with the
@njit decorator, this enables SIMD-level parallelism through Numba's
LLVM backend.
fn array_operations() {
let a = zeros(10)
let b = ones(10)
let c = linspace(0, 1, 100)
let d = arange(0, 10, 1)
let e = eye(3)
return a
}
@njit(cache=True)
def array_operations():
a = np.zeros(10)
b = np.ones(10)
c = np.linspace(0, 1, 100)
d = np.arange(0, 10, 1)
e = np.eye(3)
return a
Array operations combined with @njit are automatically compiled to
optimized machine code. For explicit parallel loops, use the @parallel
decorator with prange:
@njit(parallel=true)
fn parallel_sum(arr: List[Float]) -> Float {
let total = 0.0
for i in prange(0, len(arr)) {
total += arr[i]
}
return total
}
14. Constant Folding
The compiler evaluates constant expressions at compile time. Literal arithmetic, string concatenation, and boolean expressions with known values are pre-computed.
fn constant_folding_demo() {
let a = 2 + 3 // Constant arithmetic
let b = 10 * 4 // Constant multiplication
let c = "hello" + " world" // String concat
let d = true and false // Boolean logic
let e = 2^10 // Power expression
return a + b
}
def constant_folding_demo():
a = (2 + 3)
b = (10 * 4)
c = ('hello' + ' world')
d = (True and False)
e = (2 ** 10)
return (a + b)
Functions containing string operations (like "hello" + " world") do
not receive @njit because Numba does not support
Python string concatenation. The compiler detects this and omits the decorator.
15. Algebraic Simplification
The compiler performs algebraic identity simplifications. Expressions involving identity elements (multiply by 1, add 0, power of 1) can be optimized.
fn algebraic_simplification(x: Float) {
let a = x * 1 // Identity multiplication
let b = x + 0 // Identity addition
let c = x * 0 // Zero multiplication
let d = x^1 // Identity power
return a + b + c + d
}
@njit(cache=True)
def algebraic_simplification(x: float):
a = (x * 1)
b = (x + 0)
c = (x * 0)
d = (x ** 1)
return (((a + b) + c) + d)
The current compiler preserves algebraic identities in the output for debugging clarity. Python and Numba handle these optimizations at runtime via their own constant-folding passes. Future compiler versions may inline these simplifications directly.
16. Mathematical Constants
MathViz provides built-in mathematical constants that compile to their numeric values or NumPy equivalents.
| MathViz Constant | Unicode Alt | Compiled Python | Value |
|---|---|---|---|
PI | π | 3.141592653589793 | Ratio of circumference to diameter |
E | - | 2.718281828459045 | Euler's number |
TAU | - | 6.283185307179586 | 2 * PI |
PHI | - | 1.618033988749895 | Golden ratio |
INF | ∞ | float('inf') | Positive infinity |
NAN | - | float('nan') | Not a number |
// Using Unicode constant
let pi_val = π // Compiles to: 3.141592653589793
let inf_val = ∞ // Compiles to: float('inf')
// Using named constants
let area = PI * radius^2
let circumference = TAU * radius
17. Decorators
While the compiler automatically injects @njit where appropriate,
you can also use explicit decorators for fine-grained control.
// Explicit JIT with options
@jit
fn compute(arr: List[Float]) -> Float {
let total = 0.0
for x in arr {
total += x * x
}
return total
}
// No-Python-mode JIT with parallelism
@njit(parallel=true)
fn parallel_sum(arr: List[Float]) -> Float {
let total = 0.0
for i in prange(0, len(arr)) {
total += arr[i]
}
return total
}
// Vectorize for element-wise ufuncs
@vectorize
fn add_one(x: Float) -> Float {
return x + 1.0
}
| Decorator | Purpose | When to Use |
|---|---|---|
@jit | General JIT compilation | Functions that may fall back to Python |
@njit | No-Python-mode JIT | Pure numeric functions (fastest) |
@njit(cache=True) | Cached JIT | Automatic -- compiler default |
@njit(parallel=true) | Parallel JIT | Loop-heavy functions with prange |
@vectorize | NumPy ufunc creation | Element-wise array operations |
18. Error Handling
MathViz supports Rust-inspired error handling with Result and
Optional types, plus try/catch blocks.
Result Type
fn divide(a: Float, b: Float) -> Result[Float, String] {
if b == 0.0 {
return Err("Division by zero")
}
return Ok(a / b)
}
// Using match with Result
let result = divide(10.0, 2.0)
match result {
Ok(value) -> print(value)
Err(msg) -> print(msg)
}
// Error propagation with ?
fn compute() -> Result[Float, String] {
let x = divide(10.0, 2.0)?
let y = divide(x, 3.0)?
return Ok(y)
}
Optional Type
let maybe_value: Optional[Int] = Some(42)
let nothing: Optional[Int] = None
// Pattern match on Optional
match maybe_value {
Some(v) -> print(v)
None -> print("No value")
}
19. Structs & Traits
Struct Definition
struct Point {
x: Float
y: Float
}
impl Point {
fn new(x: Float, y: Float) -> Point {
return Point { x: x, y: y }
}
fn distance(self, other: Point) -> Float {
let dx = self.x - other.x
let dy = self.y - other.y
return sqrt(dx*dx + dy*dy)
}
}
// Usage
let p1 = Point.new(0.0, 0.0)
let p2 = Point.new(3.0, 4.0)
let d = p1.distance(p2) // 5.0
Traits
trait Shape {
fn area(self) -> Float
fn perimeter(self) -> Float
}
struct Circle {
radius: Float
}
impl Shape for Circle {
fn area(self) -> Float {
return PI * self.radius ^ 2
}
fn perimeter(self) -> Float {
return 2.0 * PI * self.radius
}
}
20. Enums
enum Color {
Red
Green
Blue
RGB(Int, Int, Int)
}
enum Shape {
Circle(Float) // radius
Rectangle(Float, Float) // width, height
Point
}
let c = Color::RGB(255, 128, 0)
let s = Shape::Circle(5.0)
// Pattern matching with enums
fn area(shape: Shape) -> Float {
match shape {
Shape::Circle(r) -> PI * r ^ 2
Shape::Rectangle(w, h) -> w * h
Shape::Point -> 0.0
}
}
Navigation
Previous
Getting Started - Installation and first program
Next
Module System - Organizing and reusing code
Related
Scenes & Manim - Animation integration
Examples
Tutorials - Step-by-step walkthrough