Blocs try transactionnels dans ValueScript

Apr 02 2023
Les exceptions sont difficiles à corriger. Un problème particulièrement délicat qu'il est facile d'ignorer est la possibilité d'une évaluation partielle à l'intérieur des blocs try.

Les exceptions sont difficiles à corriger. Un problème particulièrement délicat qu'il est facile d'ignorer est la possibilité d'une évaluation partielle à l'intérieur trydes blocs.

Considérez le programme JavaScript suivant :

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 });

Une autre option consiste à enregistrer une copie des variables susceptibles de changer et à les restaurer sur 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. Vous ne le ferez peut-être pas parce que c'est verbeux et inutilement défensif
  2. Il nécessite une copyopération à définir
  3. Si l' copyopération existe, elle pourrait ne pas être efficace
  4. Si a.popa des effets secondaires, ces effets secondaires ne seront pas annulés

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. Extrêmement verbeux
  2. a.unPop(item)nous oblige à comprendre que cette opération est nécessaire en cas b.push(item)d'échec, ce qui est encore facile à manquer

Dans ValueScript, tryles blocs sont transactionnels : soit ils s'exécutent jusqu'à la fin, soit ils sont annulés.

Notre programme original fait ce que nous voulions sans aucune modification :

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. "Vous ne le ferez peut-être pas"
    - Le compilateur ValueScript insère automatiquement les instructions
  2. "Nécessite copyune opération"
    - ValueScript utilise la sémantique de la valeur, il utilise simplement aCopy = a, et cela équivaut à copier
  3. " copypourrait ne pas être efficace"
    - ValueScript utilise la copie sur écriture jusqu'au bout, c'est assez efficace
  4. "Les effets secondaires de a.popne seront pas annulés"
    - ValueScript n'a pas d'effets secondaires

* certaines fonctions étrangères impressionnantes pourraient inclure des opérations de retour et celles-ci seraient automatiquement appelées

ValueScript est un dialecte de TypeScript avec une sémantique de valeur. Il dispose d'un terrain de jeu en ligne comprenant une démonstration du programme de cet article , et il est open source .