Skip to content

Commit 6f5d421

Browse files
committed
docs(manual): tighten prose and reorganize reference 📚
1 parent 17bfdf7 commit 6f5d421

18 files changed

Lines changed: 228 additions & 218 deletions

‎manual/src/SUMMARY.md‎

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -20,11 +20,11 @@
2020
- [Deque](./reference/types/deque.md): A double ended queue
2121
- [MinHeap & MaxHeap](./reference/types/min-max-heap.md): Min/max Heap
2222
- [Function](./reference/types/function.md)
23-
24-
- [If-else](./reference/if-else.md)
25-
- [While loop](./reference/while-loop.md)
26-
- [For loops and comprehensions](./reference/for-loop.md)
27-
- [Functions](./reference/functions.md)
23+
- [Control flow](./reference/control-flow.md)
24+
- [If-else](./reference/if-else.md)
25+
- [While loop](./reference/while-loop.md)
26+
- [For loops and comprehensions](./reference/for-loop.md)
27+
- [Logical operators](./reference/logical-operators.md)
2828
- [Memory Management](./reference/memory-management.md)
2929

3030
# Features

‎manual/src/features/augmented-assignment.md‎

Lines changed: 5 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
# Augmented assignment
22

3-
In Andy C++ you can augment assignment operators to quickly perform operations on existing variables like you might expect from any language.
3+
Andy C++ supports augmented assignment for operations on existing variables.
44

5-
In this example we're augmenting the assignment operator with another operator to quickly increment a number.
5+
This example increments a number with augmented assignment.
66

77
```
88
let my_number = 3;
@@ -13,15 +13,13 @@ assert_eq(my_number, 8);
1313

1414
## Optimization
1515

16-
You might expect `list ++= [1,2,3]` desugar to something like `list = list ++ [1,2,3]` but this would be needlessly inefficient. This is why
17-
languages like Andy C++ have special handling for some of these assignment operators. For instance the earlier example simply appends `[1,2,3]` to
18-
list without creating an intermediary list first.
16+
You might expect `list ++= [1,2,3]` to desugar to `list = list ++ [1,2,3]`, but that would waste work. Andy C++ handles some augmented assignments directly. In this case, it appends `[1,2,3]` without creating an intermediate list.
1917

2018
## Flexibility
2119

2220
Note: I stole this feature from [Noulith](https://github.com/betaveros/noulith).
2321

24-
Augmented assignment is not limited to built in operators, you can also use built in function or user created functions to augment assignment. Consider the following example:
22+
Augmented assignment also works with built-in functions and user-defined functions. For example:
2523

2624
```ndc
2725
let x = 3;
@@ -30,7 +28,7 @@ x f= 5; // similar to: x = f(x, 5);
3028
assert_eq(x, 8);
3129
```
3230

33-
A common situation where you might want to use is when finding the highest or lowest value in an iteration:
31+
One common use case is tracking the highest or lowest value in a loop:
3432

3533
```ndc
3634
let lowest, highest = Inf, -Inf;

‎manual/src/features/memoization.md‎

Lines changed: 5 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
# Memoization
22

3-
Andy C++ natively supports memoization through the `pure` keyword. Declaring a function as `pure` indicates that
4-
it has no side effects and always produces the same output for the same inputs. This allows the language to
5-
automatically cache and reuse results, improving performance for repeated calls with the same arguments.
3+
Andy C++ supports memoization through the `pure` keyword. Mark a function as `pure` when it has no side effects and returns the same output for the same inputs. Andy C++ can then cache and reuse previous results.
64

75
### Syntax
86

9-
You can mark both named and anonymous functions as `pure`:
7+
Mark both named and anonymous functions as `pure`:
108

119
```ndc
1210
pure fn add(x, y) {
@@ -16,18 +14,15 @@ pure fn add(x, y) {
1614
let multiply = pure fn (x, y) { x * y };
1715
```
1816

19-
> **Note:** the interpreter does not perform any checks to see if the function is actually pure. It's your
20-
> responsibility to ensure that functions don't have side-effects.
17+
> **Note:** The interpreter does not check whether a function is actually pure. You must avoid side effects yourself.
2118
2219
### Performance: keep memoization keys small
2320

2421
The cache key is computed by hashing **all arguments**. For container types like maps and lists this
2522
is an O(n) operation proportional to the number of elements. Passing large containers as arguments
26-
to a `pure fn` therefore adds hashing overhead on every call — even on cache hits.
23+
to a `pure fn` therefore adds hashing overhead on every call, even on cache hits.
2724

28-
If a container is large and doesn't change between recursive calls (e.g. a lookup table or graph),
29-
capture it as an **upvalue** instead of passing it as an argument. The upvalue is not part of the
30-
cache key, so the memoization cost is proportional only to the arguments that actually vary.
25+
If a container is large and does not change between recursive calls, such as a lookup table or graph, capture it as an **upvalue** instead of passing it as an argument. The upvalue is not part of the cache key, so memoization cost depends only on the arguments that change.
3126

3227
```ndc
3328
// Slow: `graph` is hashed on every call

‎manual/src/features/method-call-syntax.md‎

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,10 +7,10 @@
77
```ndc
88
let l = [50, 40, 20, 40, 10];
99
10-
// Usually you might write something like this
10+
// A plain function-call version
1111
let x = reduce(map(sorted(l), fn(x) => x + 5), fn(a, b) => a * b);
1212
13-
// It's much easier to read and write this type of code using method call syntax
13+
// The same code with method call syntax
1414
let y = l.sorted
1515
.map(fn(x) => x + 5)
1616
.reduce(fn(a, b) => a * b);
Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
# Control flow
2+
3+
Control flow in Andy C++ uses expressions and keywords instead of punctuation-heavy syntax. This section covers branching, loops, and the lazy logical operators that often appear in conditions.

‎manual/src/reference/for-loop.md‎

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# For loop
22

3-
For loops are where Andy C++ gets a little spicier. First let's look at some basic examples:
3+
Start with a basic `for` loop:
44

55
```ndc
66
for n in 1..=100 {
@@ -16,7 +16,7 @@ for n in 1..=100 {
1616
}
1717
```
1818

19-
You can combine multiple iterations in a single loop:
19+
You can combine multiple iterators in one loop:
2020

2121
```ndc
2222
let drinks = ["Coffee", "Tea", "Juice"];
@@ -28,7 +28,7 @@ for drink in drinks, dessert in desserts {
2828
}
2929
```
3030

31-
Finally you can also add one or more guards. The example below finds all pairs of numbers from 1 until 10 that have an even sum.
31+
You can also add one or more guards. This example finds all pairs from `1..10` with an even sum.
3232

3333
```ndc
3434
for x in 1..10, y in 1..10, if (x + y) % 2 == 0 {
@@ -38,16 +38,16 @@ for x in 1..10, y in 1..10, if (x + y) % 2 == 0 {
3838

3939
## For comprehensions
4040

41-
The same features, using a similar syntax, can also be used to produce lists on the go using list comprehensions.
41+
You can use the same syntax in a list comprehension.
4242

4343
```ndc
44-
// To produce a series fo perfect squares
44+
// Produce a series of perfect squares
4545
let perfect_squares = [x * x for x in 1..10];
4646
4747
assert_eq([1,4,9,16,25,36,49,64,81,100], perfect_squares);
4848
```
4949

50-
Once again the earlier example can be used to produce actual pairs as follows:
50+
The earlier example can also produce pairs:
5151

5252
```ndc
5353
let pairs_with_even_sum = [x, y for x in 1..10, y in 1..10, if (x + y) % 2 == 0]

‎manual/src/reference/functions.md‎

Lines changed: 0 additions & 119 deletions
This file was deleted.
Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
# Logical operators
2+
3+
Andy C++ uses the keywords `and`, `or`, and `not` for logical operators. If you are coming from Rust, write `and` and `or` instead of `&&` and `||`.
4+
5+
```ndc
6+
let ready = has_input and not failed;
7+
let retry = timed_out or disconnected;
8+
```
9+
10+
## Short-circuiting
11+
12+
`and` and `or` are lazy. Andy C++ evaluates the right-hand side only when it needs that value to decide the result.
13+
14+
```ndc
15+
let x = 0;
16+
17+
true and { x = x + 1; false };
18+
false and { x = x + 1; false };
19+
true or { x = x + 1; false };
20+
false or { x = x + 1; false };
21+
22+
assert_eq(x, 2);
23+
```
24+
25+
`false and ...` stops at `false`, and `true or ...` stops at `true`.
26+
27+
## Precedence
28+
29+
`and` binds tighter than `or`.
30+
31+
```ndc
32+
let a = true or true and false; // true
33+
let b = false and true or true; // true
34+
```
35+
36+
That means Andy C++ reads those expressions as:
37+
38+
```ndc
39+
let a = true or (true and false);
40+
let b = (false and true) or true;
41+
```
42+
43+
## Bitwise operators
44+
45+
Boolean values also support the non-lazy operators `&`, `|`, and `~`.
46+
47+
Use `and` and `or` when you want short-circuiting. Use `&` and `|` when you need both sides to run.

‎manual/src/reference/types/boolean.md‎

Lines changed: 1 addition & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -17,24 +17,4 @@ Operators defined for booleans:
1717
| `and` | lazy logical and |
1818
| `not` | logical not like `!` but lower precedence |
1919

20-
## Lazy evaluation of `and` and `or`
21-
22-
The `and` and `or` operators are **lazy**, meaning their operands are evaluated only when necessary to determine the result.
23-
This differs from bitwise operators (`|`, `&`, `~`), which always evaluate both operands.
24-
25-
```ndc
26-
fn a() {
27-
print("a invoked");
28-
false
29-
};
30-
31-
fn b() {
32-
print("b invoked");
33-
true
34-
};
35-
36-
// Only "a invoked" is printed because evaluation is lazy.
37-
if a() and b() {
38-
// ...
39-
}
40-
```
20+
See [Logical operators](../logical-operators.md) for short-circuiting and precedence rules.

0 commit comments

Comments
 (0)