- Quote a B2B order: if, else-if chain and if force
- Shipping rates by weight and zone with case
- Order state machine with switch
- Same code for DEV, UAT and PROD with mode
- Paginate a REST export with for
- Retry a failing call with while and exponential backoff
- Drain a print queue with repeat (do-while)
- First free meeting slot: nested loops, break and continue
- Ask three suppliers at once with parallel
- Reserve stock without overselling: synchronized
Quote a B2B order: if, else-if chain and if force
Pick the VAT rate with an if / else-if chain, add an optional gift with an if without else, and use if force so the audit trail keeps both the VIP and the standard price while only the chosen one is returned.
#1. A B2B order and its customer; -> "[amount]" 1840; -> "[vip]" true; -> "[country]" "DE"; #2. Classic if with an else block, nested for an else-if chain; -> "[vat_rate]" (if (equal [country] "FR") {20} {if (equal [country] "DE") {19} {0}}); #3. if without else returns an empty string when the condition is false; -> "[gift]" (if (> [amount] 5000) {"free training day"}); #4. if force runs BOTH blocks and returns the chosen one: the audit gets both prices; -> "[price]" (if force ([vip]) { -> "[vip_price]" (math round (* [amount] 0.88) 2); [vip_price]; } { -> "[std_price]" (math round (* [amount] 0.97) 2); [std_price]; }); -> "[ttc]" (math round (bd* [price] (bd+ 1 (bd/ [vat_rate] 100))) 2); concat "VAT " [vat_rate] "%, price " [price] ", with VAT " [ttc] [_n_] "gift: [" [gift] "] is empty: " (is empty [gift]) [_n_] "audit: VIP " [vip_price] " vs standard " [std_price] ", saving " (bd- [std_price] [vip_price]);
VAT 19%, price 1619.2, with VAT 1926.85 gift: [] is empty: 1 audit: VIP 1619.2 vs standard 1784.8, saving 165.6
Shipping rates by weight and zone with case
Price parcels with a case statement: the first true condition wins, so the narrow rules (over 30 kg, heavy parcels abroad) come first; shows the wrong-order trap and the null returned by a case without else.
#1. Parcels: weight in kg and destination zone; -> "[parcels]" "0.4:EU,2.5:EU,12:EU,31:EU,1.2:WORLD,8:WORLD"; -> "[out]" ""; for (-> "[i]" 1) (<= [i] (atom size [parcels] ",")) (++ "[i]") { -> "[p]" (atom get [parcels] [i] ","); -> "[kg]" (atom get [p] 1 ":"); -> "[zone]" (atom get [p] 2 ":"); #2. case returns the block of the FIRST true condition: put the narrow rules first; -> "[rate]" (case (> [kg] 30) {"refused: over 30 kg"} (and (equal [zone] "WORLD") (> [kg] 5)) {"42.00"} (equal [zone] "WORLD") {"18.50"} (<= [kg] 0.5) {"4.90"} (<= [kg] 5) {"7.90"} {"13.90"} ); -> "[out]" (concat [out] [kg] " kg " [zone] " -> " [rate] [_n_]); }; #3. Wrong order: the wide rule hides the narrow one; -> "[bad]" (case (equal "WORLD" "WORLD") {"18.50"} (> 8 5) {"42.00"}); #4. No else and no true condition gives null; -> "[none]" (case (> 1 2) {"x"} (> 1 3) {"y"}); concat [out] "8 kg WORLD with the rules in the wrong order: " [bad] [_n_] "no match and no else: " [none] ", is null: " (is null [none]);
0.4 kg EU -> 4.90 2.5 kg EU -> 7.90 12 kg EU -> 13.90 31 kg EU -> refused: over 30 kg 1.2 kg WORLD -> 18.50 8 kg WORLD -> 42.00 8 kg WORLD with the rules in the wrong order: 18.50 no match and no else: , is null: 1
concatprints a null as nothing: test withis nullbefore showing a value.- Keep the rate table in a JSON document and loop on it with
json count/json select.
Order state machine with switch
Apply webhook events to an order with a switch on state+event: allowed transitions move the state, the else block rejects the others; the trap is that switch compares texts, so a quantity 2.0 sent by a form does not match the case 2.
#1. Order state machine: events received by a webhook; -> "[state]" "NEW"; -> "[events]" "pay,ship,ship,deliver,refund"; -> "[log]" ""; for (-> "[i]" 1) (<= [i] (atom size [events] ",")) (++ "[i]") { -> "[ev]" (atom get [events] [i] ","); -> "[key]" (concat [state] "+" [ev]); #2. switch compares the value with each case as a string, first match wins; -> "[next]" (switch ([key]) ("NEW+pay") {"PAID"} ("PAID+ship") {"SHIPPED"} ("SHIPPED+deliver") {"DELIVERED"} ("DELIVERED+refund") {"REFUNDED"} {concat "REJECTED"} ); if (equal [next] "REJECTED") { -> "[log]" (concat [log] [ev] ": refused in state " [state] [_n_]); } { -> "[log]" (concat [log] [state] " -> " [next] [_n_]); -> "[state]" [next]; }; }; #3. Trap: the comparison is textual, a form that sends 2.0 does not match 2; -> "[qty]" "2.0"; -> "[raw]" (switch ([qty]) ("1") {"one box"} ("2") {"two boxes"} {concat "no case for " [qty]}); -> "[fixed]" (switch ((math round [qty] 0)) ("1") {"one box"} ("2") {"two boxes"} {"other"}); concat [log] "final state: " [state] [_n_] "raw: " [raw] ", rounded first: " [fixed];
NEW -> PAID PAID -> SHIPPED ship: refused in state SHIPPED SHIPPED -> DELIVERED DELIVERED -> REFUNDED final state: REFUNDED raw: no case for 2.0, rounded first: two boxes
- Keep the transitions in a
tuto_parameter or a JSON document to change them without code. - Raise an
exceptioninstead of logging when a webhook sends an impossible transition.
Same code for DEV, UAT and PROD with mode
mode reads a server parameter by its key and runs the matching block: choose the API URL and log level from SERVER_MODE, then drive a payment module from its own stage parameter that is added, switched to PROD and LOCAL, and removed.
#1. mode reads a server parameter by its key: here the built-in SERVER_MODE; -> "[api]" (mode SERVER_MODE (PROD) {"https://api.example.com/v2"} (DEV) {"https://sandbox.example.com/v2"} {"http://localhost:8080/v2"} ); -> "[log_level]" (mode SERVER_MODE (PROD) {"ERROR"} {"DEBUG"}); #2. Any parameter works: a stage flag owned by the payment module; parameter add tuto_lang_stage UAT; -> "[uat]" (mode tuto_lang_stage (PROD) {"live keys"} (UAT) {"test keys, fake cards accepted"} {"no payment"}); #3. Change the parameter: the same code takes another branch, no redeploy; parameter update tuto_lang_stage PROD; -> "[prod]" (mode tuto_lang_stage (PROD) {"live keys"} (UAT) {"test keys, fake cards accepted"} {"no payment"}); parameter update tuto_lang_stage LOCAL; -> "[other]" (mode tuto_lang_stage (PROD) {"live keys"} (UAT) {"test keys, fake cards accepted"} {"no payment"}); parameter remove tuto_lang_stage; concat "SERVER_MODE=" (parameter get value SERVER_MODE) ": api " [api] ", log " [log_level] [_n_] "payments in UAT: " [uat] [_n_] "payments in PROD: " [prod] [_n_] "payments in LOCAL, else block: " [other] [_n_] "stage parameter removed: " (not (parameter exist tuto_lang_stage));
SERVER_MODE=DEV: api https://sandbox.example.com/v2, log DEBUG payments in UAT: test keys, fake cards accepted payments in PROD: live keys payments in LOCAL, else block: no payment stage parameter removed: 1
- The first parameter of
modeis the parameter KEY, not its value:mode SERVER_MODE (PROD) {...}. - Check
parameter existbeforemodeon a parameter that may not be deployed yet.
Paginate a REST export with for
Plan the calls of a paginated export (1037 rows, pages of 250) with a for loop that steps by the page size, then use a for whose init and increment blocks move two cursors at once to check a mirror reference code.
#1. Export 1037 rows of a REST API by pages of 250; -> "[total]" 1037; -> "[size]" 250; -> "[plan]" ""; -> "[pages]" 0; #2. for: init, condition, increment by a step, action; for (-> "[offset]" 0) (< [offset] [total]) (-> "[offset]" (+ [offset] [size])) { ++ "[pages]"; -> "[limit]" (math min [size] (- [total] [offset])); -> "[plan]" (concat [plan] "page " [pages] ": GET /orders?offset=" [offset] "&limit=" [limit] [_n_]); }; #3. The init and increment blocks can hold several statements: two cursors, 0-based like string substr; -> "[ref]" "AB12321BA"; -> "[mirror]" 1; for {-> "[l]" 0; -> "[r]" (- (string length [ref]) 1);} (< [l] [r]) {++ "[l]"; -- "[r]";} { if (not (equal (string substr [ref] [l] (+ [l] 1)) (string substr [ref] [r] (+ [r] 1)))) {-> "[mirror]" 0;}; }; #4. The loop variables live on after the loop; concat [plan] [pages] " calls, offset after the loop: " [offset] [_n_] [ref] " is a mirror code: " [mirror] ", same as string reverse: " (equal [ref] (string reverse [ref])) ", cursors met at " [l] "/" [r];
page 1: GET /orders?offset=0&limit=250 page 2: GET /orders?offset=250&limit=250 page 3: GET /orders?offset=500&limit=250 page 4: GET /orders?offset=750&limit=250 page 5: GET /orders?offset=1000&limit=37 5 calls, offset after the loop: 1250 AB12321BA is a mirror code: 1, same as string reverse: 1, cursors met at 4/4
string substris 0-based with an END index (Java substring):string substr "ABC" 0 1is A.- Replace the plan by real calls with
restfunctions once the endpoint exists.
Retry a failing call with while and exponential backoff
Call a service that answers 503 twice, retrying in a while loop guarded by a maximum number of attempts; each failure is caught by try, logged, and followed by a wait that doubles (100, 200, 400 ms).
#1. A remote call that fails twice with 503 then answers: simulated here; -> "[fails_before_ok]" 2; -> "[attempt]" 0; -> "[max]" 5; -> "[delay]" 100; -> "[done]" false; -> "[trace]" ""; -> "[t0]" (date current_ms); #2. while checks the condition before each turn: stop on success or after max attempts; while (and (not [done]) (< [attempt] [max])) { ++ "[attempt]"; try { if (<= [attempt] [fails_before_ok]) {exception (503) ("Service Unavailable");}; -> "[answer]" "{\"order\": 4521, \"status\": \"accepted\"}"; -> "[done]" true; -> "[trace]" (concat [trace] "attempt " [attempt] ": OK" [_n_]); } { #3. Exponential backoff: 100, 200, 400 ms...; -> "[trace]" (concat [trace] "attempt " [attempt] ": " (string regexp_extract [err] "[0-9]+: [^\n]*$" 0) ", retry in " [delay] " ms" [_n_]); wait [delay]; -> "[delay]" (* [delay] 2); } "[err]"; }; -> "[elapsed]" (- (date current_ms) [t0]); concat [trace] "success: " [done] " after " [attempt] " attempts, waited at least 300 ms: " (>= [elapsed] 300) [_n_] "answer: " [answer];
attempt 1: 503: Service Unavailable, retry in 100 ms
attempt 2: 503: Service Unavailable, retry in 200 ms
attempt 3: OK
success: 1 after 3 attempts, waited at least 300 ms: 1
answer: {"order": 4521, "status": "accepted"}- Always put a maximum in the condition of a while that waits on the outside world.
- Add a random jitter with
math randomso many clients do not retry at the same millisecond.
Drain a print queue with repeat (do-while)
Process a JSON queue of print jobs with repeat: the block runs first, then the condition is tested, so the loop takes the head, removes it with json darray and stops when the array is empty; on an empty queue the block still runs once, so it needs a guard.
#1. A queue of print jobs kept in a JSON array; json load "tuto_lang_queue" "{\"jobs\": [{\"doc\": \"invoice-881.pdf\", \"pages\": 3}, {\"doc\": \"label-12.pdf\", \"pages\": 1}, {\"doc\": \"catalog.pdf\", \"pages\": 48}]}"; -> "[printed]" 0; -> "[log]" ""; #2. repeat runs the block first, then tests the condition: do-while; repeat (> (json count "tuto_lang_queue" "/jobs") 0) { -> "[doc]" (json select "tuto_lang_queue" "/jobs[0]/doc"); -> "[printed]" (+ [printed] (json select "tuto_lang_queue" "/jobs[0]/pages")); json darray "tuto_lang_queue" "/jobs" 0; -> "[log]" (concat [log] "printed " [doc] ", left " (json count "tuto_lang_queue" "/jobs") [_n_]); }; #3. Trap: on an empty queue the block still runs once, so guard it; -> "[turns]" 0; repeat (> (json count "tuto_lang_queue" "/jobs") 0) { ++ "[turns]"; if (> (json count "tuto_lang_queue" "/jobs") 0) {json darray "tuto_lang_queue" "/jobs" 0;}; }; json unload "tuto_lang_queue"; concat [log] "pages printed: " [printed] [_n_] "turns of repeat on the empty queue: " [turns];
printed invoice-881.pdf, left 2 printed label-12.pdf, left 1 printed catalog.pdf, left 0 pages printed: 52 turns of repeat on the empty queue: 1
- Use
whilewhen the queue may be empty from the start: it tests first. - Persist the queue in a
tuto_node to survive a restart.
First free meeting slot: nested loops, break and continue
Search the first free hour of the team over the next days: continue skips weekends and busy hours, break leaves the hour loop when a slot is found, and a flag stops the day loop since break only exits the innermost loop.
#1. Busy hours of the team per day, from the shared calendar; -> "[days]" "2026-11-06,2026-11-07,2026-11-08,2026-11-09,2026-11-10"; json load "tuto_lang_busy" "{\"2026-11-06\": \"9,10,11,12,13,14,15,16\", \"2026-11-09\": \"9,11,14\", \"2026-11-10\": \"\"}"; -> "[found]" ""; -> "[checked]" 0; for (-> "[d]" 1) (<= [d] (atom size [days] ",")) (++ "[d]") { -> "[day]" (atom get [days] [d] ","); #2. continue skips the rest of this turn: no meeting on weekends; if (date is_weekend [day]) {continue;}; -> "[busy]" (json select "tuto_lang_busy" (concat "/" [day])); for (-> "[h]" 9) (<= [h] 16) (++ "[h]") { ++ "[checked]"; #Trap: atom find returns a position, and if is true only for 1 or true, so compare it; if (> (atom find [busy] [h] ",") 0) {continue;}; #3. break leaves only the inner loop; -> "[found]" (concat [day] " at " [h] ":00"); break; }; #4. So test a flag to leave the outer loop too; if (is not empty [found]) {break;}; }; json unload "tuto_lang_busy"; concat "first free slot: " [found] [_n_] "hours checked: " [checked] ", outer loop stopped on day " [d];
first free slot: 2026-11-09 at 10:00 hours checked: 10, outer loop stopped on day 4
- Trap:
atom findreturns a position (1, 2, 3...) andifis true only for 1 or true, so compare with> 0. - break and continue also work inside
json parse_array,csv parseandsql parse.
Ask three suppliers at once with parallel
Fan out three price requests that take 400 to 600 ms each: parallel runs the blocks at the same time, returns one JSON item per block with status OK or KO (a timeout of one supplier does not stop the others), and the blocks share the variables of the caller.
#1. Ask three suppliers for a price at the same time: each call takes 400 to 600 ms; -> "[t0]" (date current_ms); json load "tuto_lang_quotes" (parallel { wait 600; -> "[p_acme]" 18.40; "acme:18.40"; } { wait 400; -> "[p_globex]" 17.95; "globex:17.95"; } { wait 500; exception (504) ("initech timeout"); }); -> "[elapsed]" (- (date current_ms) [t0]); #2. One JSON item per block, in the order of the blocks, with status OK or KO; -> "[report]" ""; -> "[failed]" 0; for (-> "[i]" 0) (< [i] (json count "tuto_lang_quotes" "/")) (++ "[i]") { -> "[st]" (json select "tuto_lang_quotes" (concat "/[" [i] "]/status")); -> "[res]" (json select "tuto_lang_quotes" (concat "/[" [i] "]/result")); #A KO block holds the error text: keep its last line; if (equal [st] "KO") {++ "[failed]"; -> "[res]" (string regexp_extract [res] "[0-9]+: [^\n]*$" 0);}; -> "[report]" (concat [report] "block " (+ [i] 1) ": " [st] " " [res] [_n_]); }; json unload "tuto_lang_quotes"; #3. The blocks share the variables of the caller; concat [report] [failed] " supplier failed, best price: " (math min [p_acme] [p_globex]) [_n_] "1.5 s of calls done in under 0.9 s: " (< [elapsed] 900);
block 1: OK acme:18.40 block 2: OK globex:17.95 block 3: KO 504: initech timeout 1 supplier failed, best price: 17.95 1.5 s of calls done in under 0.9 s: 1
- Each block can
executea script:parallel {execute "tuto.x.exe" ...;} {...}. - Shared variables are written by several threads: protect read-modify-write with
synchronized.
Reserve stock without overselling: synchronized
Four customers order 2 of the last 5 items at the same time: the check and the decrement run in the same synchronized key, so exactly two orders win; an exception inside the block releases the lock for the next caller.
#1. 5 items left, four customers order 2 items at the same second; -> "[stock]" 5; -> "[accepted]" 0; -> "[refused]" 0; #2. Check then decrement inside the same lock: no overselling; -> "[reserve]" (mql { synchronized ("tuto_lang_stock_sku42") { if (>= [stock] 2) { wait 50; -> "[stock]" (- [stock] 2); ++ "[accepted]"; "reserved"; } { ++ "[refused]"; "out of stock"; }; }; }); json load "tuto_lang_orders" (parallel {eval [reserve];} {eval [reserve];} {eval [reserve];} {eval [reserve];}); #The order of the winners changes from run to run, so count the answers; -> "[statuses]" ""; for (-> "[i]" 0) (< [i] 4) (++ "[i]") {-> "[statuses]" (concat [statuses] (json select "tuto_lang_orders" (concat "/[" [i] "]/result")) ",");}; json unload "tuto_lang_orders"; #3. An error inside the block releases the lock: the next caller is not blocked; -> "[bad]" (try {synchronized ("tuto_lang_stock_sku42") {exception (422) ("quantity must be positive");};} {string regexp_extract [e] "[0-9]+: [^\n]*$" 0} "[e]"); -> "[after]" (synchronized ("tuto_lang_stock_sku42") {concat "lock free, stock " [stock];}); concat "answers: " (atom count [statuses] "reserved" ",") " reserved, " (atom count [statuses] "out of stock" ",") " out of stock" [_n_] [accepted] " accepted, " [refused] " refused, stock left " [stock] [_n_] "bad order: " [bad] [_n_] [after];
answers: 2 reserved, 2 out of stock 2 accepted, 2 refused, stock left 1 bad order: 422: quantity must be positive lock free, stock 1
- Use one key per resource (
tuto_lang_stock_sku42), not one global key, to keep the other products parallel. - The winners change from run to run: count results, never rely on the order of the blocks.
