Các khối thử giao dịch trong ValueScript

Apr 02 2023
Các trường hợp ngoại lệ rất khó để có được đúng. Một vấn đề đặc biệt phức tạp dễ bị bỏ qua là khả năng đánh giá một phần bên trong các khối thử.

Các trường hợp ngoại lệ rất khó để có được đúng. Một vấn đề đặc biệt phức tạp dễ bị bỏ qua là khả năng đánh giá một phần bên trong trycác khối.

Hãy xem xét chương trình JavaScript sau:

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

Một tùy chọn khác là lưu một bản sao của các biến có thể thay đổi và khôi phục chúng trên 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. Bạn có thể không làm điều đó vì nó dài dòng và cảm thấy phòng thủ không cần thiết
  2. Nó yêu cầu một copyhoạt động được xác định
  3. Nếu copyhoạt động tồn tại, nó có thể không hiệu quả
  4. Nếu a.popcó tác dụng phụ, những tác dụng phụ đó sẽ không được hoàn nguyê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. Cực kỳ dài dòng
  2. a.unPop(item)yêu cầu chúng tôi hiểu rằng thao tác này là cần thiết khi b.push(item)thất bại, điều này vẫn dễ bỏ sót

Trong ValueScript, trycác khối là giao dịch — chúng có thể chạy đến khi hoàn thành hoặc được hoàn nguyên.

Chương trình ban đầu của chúng tôi thực hiện những gì chúng tôi muốn mà không có bất kỳ sửa đổi nào:

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. “Bạn có thể không làm được”
    — Trình biên dịch ValueScript tự động chèn các hướng dẫn
  2. “Yêu cầu copythao tác”
    — ValueScript sử dụng ngữ nghĩa giá trị, nó chỉ sử dụng aCopy = a, và điều này tương đương với việc sao chép
  3. copycó thể không hiệu quả”
    — ValueScript sử dụng tính năng sao chép trên ghi hoàn toàn, nó khá hiệu quả
  4. “Tác dụng phụ của a.popsẽ không được hoàn nguyên”
    — ValueScript không có tác dụng phụ

* một số chức năng nước ngoài tuyệt vời có thể bao gồm các hoạt động hoàn nguyên và chúng sẽ tự động được gọi

ValueScript là một phương ngữ của TypeScript với ngữ nghĩa giá trị. Nó có một sân chơi trực tuyến bao gồm cả phần trình diễn chương trình của bài viết này và nó là mã nguồn mở .