Python and Viv · Errors
Exceptions against checked results
What to notice
- Viv has no exceptions and no
try. A function that can fail returns a flag, its value and a message (return false, 0, "why"), and the caller tests the flag. The message here is written to match the one Python'sintraises. int("abc")stops a Viv run with CPython's message, and nothing can catch it, soparse_agechecks the text withisdigitbefore converting.stop("...")is Viv'sraisefor a condition that should never happen: it ends the run witherror:, the message and the line, and exit status 1, in every engine. The program's check passes, so it does not run here.- Dividing a double by zero in Viv gives
infornan, as in C, where Python raisesZeroDivisionError;ratiotests for zero first. (Viv's%and//by zero stop the run, as Python's raise.) - Viv has no
nanconstant;float("nan")works in both. stock[item]for a missing key stops a Viv run, as it raisesKeyErrorin Python;item in stocktests first.
Python checked.py · 42 lines
Viv checked.viv · 65 lines
py2viv refuses checked.py
1 a function that can fail
4def parse_age(text):
5 value = int(text)
6 if value < 0:
7 raise ValueError(f"age cannot be negative: {value}")
8 return value
2def parse_age(text) {
3 body = text
4 if text.startswith("-") {
5 body = text[1:]
6 }
7 if not body.isdigit() {
8 return false, 0, f"invalid literal for int() with base 10: {text!r}"
9 }
10 value = int(text)
11 if value < 0 {
12 return false, 0, f"age cannot be negative: {value:d}"
13 }
14 return true, value, ""
15}
py2viv refuses this program:
checked.py:12:5: not numeric Python: `try`/`except`
try:
^^^^
Check the condition and stop with `assert`.
checked.py:20:5: not numeric Python: `try`/`except`
try:
^^^^
Check the condition and stop with `assert`.
checked.py:25:7: not numeric Python: printing a value of unknown type (it comes from a construct refused elsewhere)
print(ratio(1.0, 4.0), ratio(1.0, 0.0))
^^^^^^^^^^^^^^^
Fix the refusal that produced it.
checked.py:30:5: not numeric Python: `try`/`except`
try:
^^^^
Check the condition and stop with `assert`.
checked.py:36:13: not numeric Python: d.values() outside a for loop header
total = sum(stock.values())
^^^^^^^^^^^^^^
Loop over it: `for k, v in d.items():` (unrolled per key).
5 constructs outside the numeric subset (tools/py2viv/SUBSET.md) 2 the caller handles the failure
11for text in ["42", "-3", "abc", "7"]:
12 try:
13 age = parse_age(text)
14 print(f"{text!r}: age {age}")
15 except ValueError as e:
16 print(f"{text!r}: refused ({e})")
18for text in ["42", "-3", "abc", "7"] {
19 ok, age, why = parse_age(text)
20 if ok {
21 print(f"{text!r}: age {age:d}")
22 }
23 else {
24 print(f"{text!r}: refused ({why})")
25 }
26}
(refused)
3 division by zero
19def ratio(a, b):
20 try:
21 return a / b
22 except ZeroDivisionError:
23 return float("nan")
24
25print(ratio(1.0, 4.0), ratio(1.0, 0.0))
29def ratio(a, b) {
30 if b == 0 {
31 return float("nan")
32 }
33 return a / b
34}
35
36print(fmt(ratio(1.0, 4.0)), fmt(ratio(1.0, 0.0)))
(refused)
4 a missing key
28stock = {"apple": 3, "pear": 0}
29for item in ["apple", "plum"]:
30 try:
31 print(item, stock[item])
32 except KeyError:
33 print(item, "not stocked")
39stock = map()
40stock["apple"] = 3
41stock["pear"] = 0
42for item in ["apple", "plum"] {
43 if item in stock {
44 print(item, stock[item])
45 }
46 else {
47 print(item, "not stocked")
48 }
49}
(refused)
5 a check that should never fail
36total = sum(stock.values())
37if total != 3:
38 raise RuntimeError(f"stock total is {total}, expected 3")
39print("stock total checked")
52total = sum(values(stock))
53if total != 3 {
54 stop(f"stock total is {total:d}, expected 3")
55}
56print("stock total checked")
(refused)
6 checks
42assert parse_age("42") == 42
59test "parse" {
60 ok, age, why = parse_age("42")
61 assert_true(ok and age == 42)
62}
(refused)
What they print
identical — the two programs print the same text.
Dimmed lines are left out of the comparison. Each Viv test block prints one PASS line; the Python checks the same facts with assert, which prints nothing.
$ python3 checked.py
'42': age 42'-3': refused (age cannot be negative: -3)'abc': refused (invalid literal for int() with base 10: 'abc')'7': age 70.25 nanapple 3plum not stockedstock total checked
$ viv run checked.viv
'42': age 42'-3': refused (age cannot be negative: -3)'abc': refused (invalid literal for int() with base 10: 'abc')'7': age 70.25 nanapple 3plum not stockedstock total checkedPASS parse