Saltar al contenido

31 · Recarga en caliente

Undo/Redo y Casos Avanzados

Viaje en el tiempo por el historial de swaps via :undo / :redo / :history, más reload transparente en bucles cerrados sin yield y referencias de closure capturadas fuera del live-binding.

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.

formula.zolo
Playground
// 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.

main.zolo
Playground
// 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.

worker.zolo
Playground
// 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.

main.zolo
Playground
// 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.

Funciones anónimas capturadas fuera del enlace dinámico

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.

greeter.zolo
Playground
// 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.

main.zolo
Playground
// 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.

Índice global

Encuentra tu camino por Zolo

Prueba una idea

Empieza aquí

9 resultados

9 resultados

enespt-br