Improve tutorial

This commit is contained in:
Andrew Morris
2023-03-29 13:16:07 +11:00
parent 66433522f9
commit 922b98036a
9 changed files with 92 additions and 55 deletions

View File

@@ -5,6 +5,8 @@ const files: Record<string, string | nil> = {
...pick(raw, [
'/tutorial/hello.ts',
'/tutorial/valueSemantics.ts',
'/tutorial/cantMutateCaptures.ts',
'/tutorial/classBehavior.ts',
'/tutorial/revertOnCatch.ts',
'/tutorial/binaryTree.ts',
]),

View File

@@ -11,6 +11,6 @@ export default Object.fromEntries(await Promise.all(
entries.map(async ([path, module]) => {
const prefix = './root';
assert(path.startsWith(prefix));
return [path.slice('./root'.length), await module()];
return [path.slice('./root'.length), (await module()).trim()];
}),
));

View File

@@ -1,24 +0,0 @@
export default function main() {
let idGen = new IdGenerator();
return [
idGen.generate(),
idGen.generate(),
idGen.generate(),
];
}
class IdGenerator {
nextId: number;
constructor() {
this.nextId = 1;
}
generate() {
const result = this.nextId;
this.nextId++;
return result;
}
}

View File

@@ -1,16 +0,0 @@
export default function main() {
let nextId = 1;
function generateId() {
const result = nextId;
nextId++;
return result;
}
return [
generateId(),
generateId(),
generateId(),
];
}

View File

@@ -0,0 +1,28 @@
// ValueScript is like TypeScript without side effects. We achieve this by
// deviating from JavaScript in three key ways.
//
// 2. Captured variables cannot be mutated
export default function main() {
let counter = 0;
const next = () => {
counter++;
return counter;
};
return [next(), next(), next()];
// JavaScript: [1, 2, 3]
// ValueScript: Compilation error
}
// Both JavaScript and ValueScript allow:
// - Mutating variables
// - Capturing variables
//
// But in ValueScript you can only do one or the other.
//
// By allowing both, JavaScript allows the `next` function to return different
// values each time it is called. This is a side effect.
//
// However, you can get this kind of behavior in ValueScript by using a class...

View File

@@ -0,0 +1,33 @@
// ValueScript is like TypeScript without side effects. We achieve this by
// deviating from JavaScript in three key ways.
//
// 3. When `this` changes inside `counter.next()`, the updated `this` value is
// used to mutate `counter` when the method returns.
export default function main() {
let counter = new Counter();
return [counter.next(), counter.next(), counter.next()];
// JavaScript: [1, 2, 3]
// ValueScript: [1, 2, 3]
}
class Counter {
value = 0;
next() {
this.value++;
return this.value;
}
}
// This difference is more subtle - the program as a whole behaves the same but
// the implementation is different.
//
// In JavaScript, when `this.value++` updates `this`, it is doing that directly
// on the `counter` object.
//
// In ValueScript, `this` is just a variable, and variable mutation is always
// local. Instead, methods have an implicit extra output for `this` (similar to
// `this` being an implicit input in both languages). That extra output is used
// to mutate the variable on the left side of the dot when the method returns.

View File

@@ -1,12 +1,13 @@
// Welcome to the ValueScript playground!
//
// This playground also acts as a tutorial by describing a variety of
// examples. All examples are editable with live updates to their outputs.
//
// Keeping with tradition, here is the hello world program.
// ValueScript is a dialect of TypeScript. We use the same syntax and many
// simple programs work exactly the same way:
export default function main() {
return "Hello world!";
}
// When you're ready to continue, click next below.
// You can freely edit these examples and their outputs will update in
// real-time.
//
// When you're ready, click next below to see a bit more complexity.

View File

@@ -1,3 +1,7 @@
// We also deviate from JavaScript in a few other ways:
//
// - Try blocks are transactional
export default function () {
let x = 0;
@@ -7,12 +11,16 @@ export default function () {
} catch {}
return x;
// TypeScript: 1
// JavaScript: 1
// ValueScript: 0
}
// In ValueScript, a try block is a transaction - it either runs to
// completion, or it is reverted. This is impractical in TypeScript,
// but in ValueScript all we have to do is snapshot the variables and
// restore from them on catch. This works because all mutation is
// local - nothing else can be affected.
// When the exception is thrown above, the value of `x` is reverted to the
// value before the `try` block. Value semantics is very important here. Without
// it, you'd need to do something much more heavy like snapshot the entire
// virtual machine. In ValueScript, we just take a snapshot of each variable
// that is mutated inside the `try` block and restore it on `catch`. You can see
// this in the assembly as `%snap_x`.
//
// Note: Method calls don't yet generate snapshots. This should be fixed soon.
// In the meantime you can workaround it by adding `myClass = myClass;`.

View File

@@ -1,15 +1,20 @@
// ValueScript is like TypeScript without side effects. We achieve this by
// deviating from JavaScript in three key ways.
//
// 1. Value semantics
export default function main() {
const leftBowl = ["apple", "mango"];
const rightBowl = leftBowl;
let rightBowl = leftBowl;
rightBowl.push("peach");
return leftBowl.includes("peach");
// TypeScript: true
// JavaScript: true
// ValueScript: false
}
// In TypeScript, `leftBowl` and `rightBowl` are the same object, and that
// In JavaScript, `leftBowl` and `rightBowl` are the same object, and that
// object changes. In ValueScript, objects are just data, they don't change.
// When you change `rightBowl`, you are changing the *variable* and therefore
// `leftBowl` doesn't change.