Debug
The Debug module provides utilities for debugging Kit programs. These functions help you trace values through pipelines, mark unimplemented code, and get source location information.
Development Only
Debug functions are intended for development and debugging purposes.
Functions like Debug.todo and Debug.unreachable
will panic at runtime if executed.
Tracing
Debug.trace
String -> a -> a
Prints a message along with the given value to stderr, then returns the value unchanged.
Useful for debugging pipelines without breaking the data flow.
# Simple tracing
result = Debug.trace "value is" 42
# Prints: [TRACE] value is: 42
# result = 42
# Tracing in a pipeline
numbers = [1, 2, 3, 4, 5]
result = numbers
|> filter (fn(x) => x > 2)
|> Debug.trace "after filter"
|> map (fn(x) => x * 2)
|> Debug.trace "after map"
# Prints:
# [TRACE] after filter: [3, 4, 5]
# [TRACE] after map: [6, 8, 10]
Side Effects
Debug.tap
(a -> ()) -> a -> a
Applies a function to the value for its side effects, then returns the value unchanged.
Useful for logging, assertions, or any side-effect in the middle of a pipeline.
# Custom logging in a pipeline
log-length = fn(xs) => println "Length: ${length xs}"
result = [1, 2, 3]
|> map (fn(x) => x * 2)
|> Debug.tap log-length
|> filter (fn(x) => x > 2)
# Prints: Length: 3
# result = [4, 6]
# Using with an inline function
data = {name: "Alice", age: 30}
|> Debug.tap (fn(r) => println "Processing: ${r.name}")
# Prints: Processing: Alice
Placeholders
Debug.todo
String -> a
Marks code as unimplemented. When executed, it will panic with the given message.
Useful as a placeholder during development to indicate incomplete code paths.
# Placeholder for unimplemented functionality
process-data = fn(data) =>
match data.format
| "json" -> parse-json data.content
| "xml" -> Debug.todo "XML parsing not yet implemented"
| "csv" -> Debug.todo "CSV parsing coming soon"
| _ -> Debug.todo "Unknown format"
# If xml format is passed:
# PANIC: TODO: XML parsing not yet implemented
Debug.unreachable
String -> a
Marks code that should never be reached. When executed, it will panic with the given message.
Useful for exhaustive pattern matching where you know certain cases are impossible.
# Marking impossible cases
get-sign = fn(n) =>
match compare n 0
| Lt -> "negative"
| Eq -> "zero"
| Gt -> "positive"
# Validating invariants
safe-head = fn(xs) =>
if is-empty? xs
then Debug.unreachable "safe-head called on empty list"
else head xs
# If unreachable code is executed:
# PANIC: UNREACHABLE: safe-head called on empty list
Source Info
Debug.source-location
a
Returns source location information including the file path, line number, and column number
where it is called. Returns a record with
file, line, and column fields.
# Get current source location
loc = Debug.source-location
println "File: ${loc.file}"
println "Line: ${loc.line}"
println "Column: ${loc.column}"
# Output:
# File: /path/to/script.kit
# Line: 5
# Column: 7
# Useful for custom error messages
my-assert = fn(condition, message) =>
if not condition
loc = Debug.source-location
panic "Assertion failed at ${loc.file}:${loc.line} - ${message}"