Procedures and Scopes

Table of Contents

1. Default Parameters and Named Arguments

We can give default value to parameters.

  // b has default value 1, its type is inferred
  // c has default value "hello", and has type string
  my_proc :: proc(a: int, b := 1, c: string = "hello") {}

  // we can call with labels
  my_proc(
      a = 7,
      c = "Yes",
  )
  my_proc(
      7, // a = 7, b is still default
      c = "Yes",
  )

Note, parameters are immutable. To modify parameters, we can create a copy of parameter and assign it to a variable with same name.

  div :: proc(n: f32, d: f32) -> f32 {
      n := n // this line
      n = n / d
      return n
  }

To modify the data, we can pass as pointer.

1.1. Immutable Reference By Default

Note: A parameter that is larger than 16 bytes will automatically be passed as an immutable reference.

2. Multiple Return Values

Return as a tuple.

  swap :: proc(n: int, m: int) -> (int, int) {
      return m, n
  }

By default, return values can be ignored. If you want to force users to handle return values, we can add result-requiring tags.

  @require_results
  swap :: proc(n: int, m: int) -> (int, int) {
      return m, n
  }

3. Named Return Values

We can give names to return values, they act like normal variables pre-declared.

  div :: proc(n: f32, d: f32) -> (res: f32, ok: bool) {
      if d == 0 {
          return
      }

      res = (n / d)
      ok = true
      return
  }

4. Nested Procedures and Captured Variables

We can declare a procedure within a procedure. Such procedures can use global variables and constants, but not variables declared locally in parental procedure.

4.1. Static Variables within Procedures

We can declare static variables within procedures with @static tag.

  @static my_var: int

A static variable bahaves like a global variable, but it’s only accessible within the procedure where it’s declared, as well as any nested procedures. Its value persists among different calls to this procedure.

5. Explicit Overloading

We can use explicit overloading to make 2 or more procedures exist under the same name. Note in the following example how length procedure is declared

  length :: proc {
      length_float2,
      length_float3,
  }

  length_float2 :: proc(v: [2]f32) -> f32 {
      return math.sqrt(v.x * v.x + v.y * v.y)
  }

  length_float3 :: proc(v: [3]f32) -> f32 {
      return math.sqrt(v.x*v.x + v.y*v.y + v.z*v.z)
  }

6. Run Procedures at Startup and Shutdown

Put @init before the startup procedure and @fini before ending procedure.

  import "core:fmt"

  main :: proc() { fmt.println("Program running") }

  @init
  startup :: proc() { fmt.println("Program started") }

  @fini
  shutdown :: proc() { fmt.println("Program shutting down") }

  // Will print
  // Program started
  // Program running
  // Program shutting down

Date: 2026-07-17 Fri