Транзакционные пробные блоки в ValueScript
Исключения трудно получить правильно. Особенно сложной проблемой, которую легко упустить из виду, является возможность частичного вычисления внутри tryблоков.
Рассмотрим следующую программу 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 });
Другой вариант — сохранить копию переменных, которые могут измениться, и восстановить их 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 });
- Вы можете не делать этого, потому что это многословно и кажется излишне оборонительным.
- Требуется
copyопределить операцию - Если
copyоперация существует, она может быть неэффективной - Если
a.popесть побочные эффекты, эти побочные эффекты не будут отменены
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 });
- Чрезвычайно многословный
a.unPop(item)требует от нас понимания, что эта операция нужна приb.push(item)сбое, что все равно легко пропустить
В ValueScript tryблоки являются транзакционными — они либо выполняются до завершения, либо возвращаются.
Наша исходная программа делает то, что мы хотели, без каких-либо модификаций:
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"],
}
- «Вы можете этого не делать»
— компилятор ValueScript автоматически вставляет инструкции - «Требуется
copyоперация»
— ValueScript использует семантику значений, он просто используетaCopy = a, и это эквивалентно копированию - «
copyможет быть неэффективным»
— ValueScript полностью использует копирование при записи, это довольно эффективно - «Побочные эффекты
a.popне будут устранены»
— ValueScript не имеет побочных эффектов
* некоторые удивительные иностранные функции могут включать операции возврата, и они будут автоматически вызываться
ValueScript — это диалект TypeScript с семантикой значений. У него есть онлайн-игровая площадка, включающая демонстрацию программы из этой статьи , и она с открытым исходным кодом .

![В любом случае, что такое связанный список? [Часть 1]](https://post.nghiatu.com/assets/images/m/max/724/1*Xokk6XOjWyIGCBujkJsCzQ.jpeg)



































