Blok Coba Transaksional di ValueScript

Apr 02 2023
Pengecualian sulit dilakukan dengan benar. Masalah yang sangat rumit yang mudah diabaikan adalah kemungkinan evaluasi parsial di dalam blok percobaan.

Pengecualian sulit dilakukan dengan benar. Masalah yang sangat rumit yang mudah diabaikan adalah kemungkinan evaluasi parsial di dalam tryblok.

Pertimbangkan program JavaScript berikut:

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

Opsi lain adalah menyimpan salinan variabel yang mungkin berubah dan memulihkannya di 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. Anda mungkin tidak melakukannya karena itu bertele-tele dan terasa defensif yang tidak perlu
  2. Ini membutuhkan copyoperasi untuk didefinisikan
  3. Jika copyoperasi itu ada, itu mungkin tidak efisien
  4. Jika a.popmemiliki efek samping, efek samping tersebut tidak akan dikembalikan

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. Sangat bertele-tele
  2. a.unPop(item)mengharuskan kita untuk memahami bahwa operasi ini diperlukan saat b.push(item)gagal, yang masih mudah terlewatkan

Di ValueScript, tryblok bersifat transaksional — blok berjalan hingga selesai atau dikembalikan.

Program asli kami melakukan apa yang kami inginkan tanpa modifikasi apa pun:

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. “Anda mungkin tidak melakukannya”
    — Kompiler ValueScript menyisipkan instruksi secara otomatis
  2. “Membutuhkan copyoperasi”
    — ValueScript menggunakan nilai semantik, hanya menggunakan aCopy = a, dan ini setara dengan penyalinan
  3. " copymungkin tidak efisien"
    — ValueScript menggunakan copy-on-write sepenuhnya, ini cukup efisien
  4. “Efek samping a.poptidak akan dikembalikan”
    — ValueScript tidak memiliki efek samping

* beberapa fungsi asing yang luar biasa mungkin termasuk operasi pengembalian dan ini akan dipanggil secara otomatis

ValueScript adalah dialek TypeScript dengan semantik nilai. Ini memiliki taman bermain online termasuk demonstrasi program artikel ini , dan open source .