Bloques Try transaccionales en ValueScript

Apr 02 2023
Las excepciones son difíciles de acertar. Un problema particularmente complicado que es fácil pasar por alto es la posibilidad de una evaluación parcial dentro de los bloques de prueba.

Las excepciones son difíciles de acertar. Un problema particularmente complicado que es fácil pasar por alto es la posibilidad de una evaluación parcial dentro de trylos bloques.

Considere el siguiente programa JavaScript:

let a = new SmallQueue(["item1"]);
let b = new SmallQueue(["item2", "item3", "item4"]);

try {
  const item = a.pop();
  b.push(item);
} catch (e) {
  console.error("Failed to move item from a to b", e);
}

console.log({ a, b });

{
  a: [],
  b: ["item2", "item3", "item4", "item1"],
}

{
  a: [],
  b: ["item2", "item3", "item4"],
}

let a = new SmallQueue(["item1"]);
let b = new SmallQueue(["item2", "item3", "item4"]);

try {
  if (b.isFull()) {
    throw new Error("b is full");
  }

  const item = a.pop();
  b.push(item);
} catch (e) {
  console.error("Failed to move item from a to b", e);
}

console.log({ a, b });

Otra opción es guardar una copia de las variables que podrían cambiar y restaurarlas en catch:

let a = new SmallQueue(["item1"]);
let b = new SmallQueue(["item2", "item3", "item4"]);

const aCopy = a.copy();
const bCopy = b.copy();

try {
  const item = a.pop();
  b.push(item);
} catch (e) {
  a = aCopy;
  b = bCopy;
  console.error("Failed to move item from a to b", e);
}

console.log({ a, b });

  1. Es posible que no lo haga porque es detallado y se siente innecesariamente a la defensiva.
  2. Requiere una copyoperación para ser definida.
  3. Si la copyoperación existe, es posible que no sea eficiente
  4. Si a.poptiene efectos secundarios, esos efectos secundarios no se revertirán.

let a = new SmallQueue(["item1"]);
let b = new SmallQueue(["item2", "item3", "item4"]);

let item;

try {
  item = a.pop();
} catch (e) {
  console.error("Failed to move item from a to b", e);
  console.log({ a, b });
  return;
}

try {
  b.push(item);
} catch (e) {
  a.unPop(item);
  console.error("Failed to move item from a to b", e);
}

console.log({ a, b });

  1. Extremadamente detallado
  2. a.unPop(item)requiere que entendamos que esta operación es necesaria cuando b.push(item)falla, lo cual aún es fácil pasar por alto

En ValueScript, trylos bloques son transaccionales: se ejecutan hasta completarse o se revierten.

Nuestro programa original hace lo que queríamos sin ninguna modificación:

let a = new SmallQueue(["item1"]);
let b = new SmallQueue(["item2", "item3", "item4"]);

try {
  const item = a.pop();
  b.push(item);
} catch (e) {
  console.error("Failed to move item from a to b", e);
}

console.log({ a, b });
{
  a: ["item1"],
  b: ["item2", "item3", "item4"],
}

  1. “Puede que no lo hagas”
    : el compilador ValueScript inserta las instrucciones automáticamente
  2. "Requiere copyoperación"
    : ValueScript usa semántica de valor, solo usa aCopy = a, y esto es equivalente a copiar
  3. “ copypodría no ser eficiente”
    : ValueScript utiliza copia en escritura hasta el final, es bastante eficiente
  4. “Los efectos secundarios de a.popno se revertirán”
    : ValueScript no tiene efectos secundarios

* algunas funciones extrañas increíbles pueden incluir operaciones de reversión y estas se llamarán automáticamente

ValueScript es un dialecto de TypeScript con semántica de valor. Tiene un patio de recreo en línea que incluye una demostración del programa de este artículo , y es de código abierto .