Undo/Redo y Casos Avanzados
En esta página
Viaje en el tiempo: :undo / :redo / :history
Cada swap exitoso guarda un checkpoint en un ring buffer por módulo
(predeterminado: 10 entradas). En el prompt de zolo dev puedes navegar ese
historial sin reescribir el código manualmente.
Comandos disponibles en el prompt:
| Comando | Efecto |
|---|---|
:undo |
Revierte el swap más reciente |
:redo |
Reaplicó el último :undo |
:history |
Lista checkpoints y contadores |
:reload <modulo> |
Fuerza el swap de un módulo |
:eval <expr> |
Compila y ejecuta una expresión en la VM viva |
:stats |
Latencias p50/p95 y conteo de swaps |
El estado vivo se preserva en ambas direcciones: un pub let count = 5
sigue siendo 5 tras :undo, aunque la versión antigua tuviera el literal 0.
La pila de redo se limpia cuando ocurre un swap "fresco" después de un :undo.
Edita la fórmula varias veces; usa :undo/:redo para navegar entre las versiones.
// Feature: a perfect target to experiment with :undo / :redo
// Syntax: edit the formula multiple times; navigate the history.
// When to use: compare variants of a function without rewriting
// each one by hand. The `ReloadHistory` keeps the source of
// previous versions and re-applies them via swap.
pub fn calc(x: int) -> int {
// Edit this formula several times during the `dev` session.
// Each save adds a checkpoint; :undo rolls back one step.
return x * 2
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
// Feature: time-travel of hot-reloads — :undo / :redo / :history
// Syntax: commands at the `zolo dev` prompt (not Zolo words).
// When to use: experiment with variants of a function and roll
// back to a previous one quickly without editing by hand.
use formula::{calc}
fn main() {
print("ENTER prints calc(10). Use :undo / :redo / :history at the prompt.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
print("calc(10) = {calc(10)}")
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
Reload en bucle cerrado sin yield
El código que nunca cede el control (sin io::read, sin sleep) sigue
recibiendo swaps: el hook de instrucción de la VM drena los reloads pendientes
cada ~2000 instrucciones. El módulo worker.zolo puede editarse mientras el
contador gira — la próxima llamada a tick ya usa la versión nueva.
Edita el mensaje en tick() mientras el bucle corre — ninguna acción manual necesaria.
// Edit this while the demo is running. Save with Ctrl+S — the next
// `tick` call uses the new code with no manual intervention.
pub fn tick(i) {
print("tick {i}: still on V1 — edit me!")
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
// Demo 02 — Hot-reload during a TIGHT CPU LOOP.
//
// zolo dev examples/zolo_live/02_tight_loop/main.zolo
//
// This script has NO `io::read` or any other yield point. It just busies
// itself spinning a counter. Yet edits to `worker.zolo` take effect
// within milliseconds — the VM instruction hook drains pending swaps
// every ~2000 instructions, transparently to the user.
//
// While running, edit `worker.zolo` (e.g. change the message format)
// and watch the output update LIVE without any user action.
use worker::{tick}
fn main() {
let i = 0
let last_print = 0
while true {
i = i + 1
if i - last_print > 5_000_000 {
tick(i)
last_print = i
}
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
Closures capturadas fuera del live-binding
Cuando una referencia de función se copia directamente en una lista o estructura
de datos (sin pasar por el thunk), el runtime igualmente actualiza esa
referencia. Al hacer el swap, el recolector recorre el heap y reemplaza cada
puntero a la función antigua por la nueva. El demo 09-closure-escape muestra
esto con un fn_queue que acumula referencias a greeter.greet antes de
cualquier edición:
Las referencias capturadas directamente también se actualizan en el swap.
// Edit me — the queued function references in main.zolo update too,
// thanks to closure-correct hot-reload.
pub fn greet(who) {
print("V1: hi {who}")
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
// Demo 04 — Closure-correct hot-reload.
//
// zolo dev examples/zolo_live/04_closure_escape/main.zolo
//
// The script captures a function reference into a queue (`fn_queue`),
// then iterates and calls them. Even though the function value escapes
// the live-binding thunk, edits to greeter.zolo still take effect on
// next call: the closure registry walks the heap and patches every
// reference to the old function value with the new one.
//
// This is the deeper guarantee — works no matter how the function got
// captured.
mod greeter
fn main() {
let fn_queue = []
// Capture the function value DIRECTLY (no live-binding thunk):
fn_queue.push(greeter.greet)
fn_queue.push(greeter.greet)
fn_queue.push(greeter.greet)
print("Press ENTER to flush the queue — or 'q' to quit.")
print("Edit greeter.zolo while waiting; queued fn refs update too.")
while true {
let line = io::read("*l")
if line is nil || line == "q" {
break
}
for f in fn_queue {
f("queued")
}
}
}
Requiere la CLI o el host de Zolo; ábrelo en el playground o ejecútalo localmente.
Consulta también