Errors and catching
Faber does not throw errors the way most languages do. A failure travels back through a dedicated error channel, declared in the signature and separate from the return value. That one decision shapes everything on this page.
The error channel#
→ declares what a function returns. ⇥ declares what it may fail with.
faber format --locale en — English reader surfacefn divide(int a, int b) → int ⇥ string {
if b ≡ 0 {
throw "division by zero"
}
return a / b
}faber format --locale la — canonical Faberfunctio divide(numerus a, numerus b) → numerus ⇥ textus {
si b ≡ 0 {
iace "division by zero"
}
redde a / b
}faber format --locale th-TH — Thaiฟังก์ชัน divide(จำนวน a, จำนวน b) → จำนวน ⇥ ข้อความ {
ถ้า b ≡ 0 {
โยน "division by zero"
}
คืน a / b
}faber format --locale zh-Hans — Simplified Chinese函数 divide(整数 a, 整数 b) → 整数 ⇥ 文本 {
如果 b ≡ 0 {
抛错 "division by zero"
}
返回 a / b
}faber format --locale zh-Hant — Traditional Chinese函式 divide(整數 a, 整數 b) → 整數 ⇥ 文字 {
若 b ≡ 0 {
拋出 "division by zero"
}
傳回 a / b
}faber format --locale vi — Vietnamesehàm divide(số a, số b) → số ⇥ văn_bản {
nếu b ≡ 0 {
ném "division by zero"
}
trả a / b
}faber format --locale ar — Arabicدالة divide(عدد a, عدد b) → عدد ⇥ نص {
إذا b ≡ 0 {
ارم "division by zero"
}
أعد a / b
}faber format --locale hi — Hindiफलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
यदि b ≡ 0 {
इधरफेंको "division by zero"
}
लौटाओ a / b
}Read it as: returns a number, or fails with a textus. The two channels are independent — the success type is not widened, wrapped, or made optional to accommodate failure. A caller reading the signature knows both shapes before looking at the body.
iace sends a value down the error channel. It is not return: it exits by the
other route.
Catching#
catch binds whatever came down the error channel.
faber format --locale en — English reader surfacefn divide(int a, int b) → int ⇥ string {
if b ≡ 0 {
throw "division by zero"
}
return a / b
}
fn tutum(int a, int b) → int {
do {
return divide(a, b)
}
catch err {
warn err
return 0
}
}
main {
print tutum(10, 2)
print tutum(10, 0)
}faber format --locale la — canonical Faberfunctio divide(numerus a, numerus b) → numerus ⇥ textus {
si b ≡ 0 {
iace "division by zero"
}
redde a / b
}
functio tutum(numerus a, numerus b) → numerus {
fac {
redde divide(a, b)
}
cape err {
mone err
redde 0
}
}
incipit {
nota tutum(10, 2)
nota tutum(10, 0)
}faber format --locale th-TH — Thaiฟังก์ชัน divide(จำนวน a, จำนวน b) → จำนวน ⇥ ข้อความ {
ถ้า b ≡ 0 {
โยน "division by zero"
}
คืน a / b
}
ฟังก์ชัน tutum(จำนวน a, จำนวน b) → จำนวน {
ทำ {
คืน divide(a, b)
}
จับ err {
เตือน err
คืน 0
}
}
เริ่ม {
บันทึก tutum(10, 2)
บันทึก tutum(10, 0)
}faber format --locale zh-Hans — Simplified Chinese函数 divide(整数 a, 整数 b) → 整数 ⇥ 文本 {
如果 b ≡ 0 {
抛错 "division by zero"
}
返回 a / b
}
函数 tutum(整数 a, 整数 b) → 整数 {
执行 {
返回 divide(a, b)
}
捕获 err {
警告 err
返回 0
}
}
入口 {
显示 tutum(10, 2)
显示 tutum(10, 0)
}faber format --locale zh-Hant — Traditional Chinese函式 divide(整數 a, 整數 b) → 整數 ⇥ 文字 {
若 b ≡ 0 {
拋出 "division by zero"
}
傳回 a / b
}
函式 tutum(整數 a, 整數 b) → 整數 {
執行 {
傳回 divide(a, b)
}
捕捉 err {
警告 err
傳回 0
}
}
入口 {
註記 tutum(10, 2)
註記 tutum(10, 0)
}faber format --locale vi — Vietnamesehàm divide(số a, số b) → số ⇥ văn_bản {
nếu b ≡ 0 {
ném "division by zero"
}
trả a / b
}
hàm tutum(số a, số b) → số {
làm {
trả divide(a, b)
}
bắt err {
cảnh_báo err
trả 0
}
}
bắt_đầu {
ghi_chú tutum(10, 2)
ghi_chú tutum(10, 0)
}faber format --locale ar — Arabicدالة divide(عدد a, عدد b) → عدد ⇥ نص {
إذا b ≡ 0 {
ارم "division by zero"
}
أعد a / b
}
دالة tutum(عدد a, عدد b) → عدد {
افعل {
أعد divide(a, b)
}
التقط err {
نبه err
أعد 0
}
}
بداية {
اعرض tutum(10, 2)
اعرض tutum(10, 0)
}faber format --locale hi — Hindiफलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
यदि b ≡ 0 {
इधरफेंको "division by zero"
}
लौटाओ a / b
}
फलन tutum(संख्या a, संख्या b) → संख्या {
करो {
लौटाओ divide(a, b)
}
पकड़ो err {
चेताओ err
लौटाओ 0
}
}
आरंभ {
दिखाओ tutum(10, 2)
दिखाओ tutum(10, 0)
}tutum has no ⇥ in its signature, and that is the point: it handles the
failure, so it cannot itself fail. The channel stops here.
catch attaches to more than do#
This is the part that surprises people arriving from other languages. catch is
not the tail of a try statement — it attaches to structured statements generally. A loop can carry its own handler:
faber format --locale en — English reader surfacemain {
const list<string> raw ← ["1", "two", "3"]
do {
for from raw const item {
const int n ← item ↦ int
print n
}
}
catch err {
warn err
}
}faber format --locale la — canonical Faberincipit {
fixum lista<textus> raw ← ["1", "two", "3"]
fac {
itera ex raw fixum item {
fixum numerus n ← item ↦ numerus
nota n
}
}
cape err {
mone err
}
}faber format --locale th-TH — Thaiเริ่ม {
คงที่ รายการ<ข้อความ> raw ← ["1", "two", "3"]
ทำ {
วน ออก raw คงที่ item {
คงที่ จำนวน n ← item ↦ จำนวน
บันทึก n
}
}
จับ err {
เตือน err
}
}faber format --locale zh-Hans — Simplified Chinese入口 {
常量 列表<文本> raw ← ["1", "two", "3"]
执行 {
遍历 取自 raw 常量 item {
常量 整数 n ← item ↦ 整数
显示 n
}
}
捕获 err {
警告 err
}
}faber format --locale zh-Hant — Traditional Chinese入口 {
定值 列表<文字> raw ← ["1", "two", "3"]
執行 {
遍歷 取自 raw 定值 item {
定值 整數 n ← item ↦ 整數
註記 n
}
}
捕捉 err {
警告 err
}
}faber format --locale vi — Vietnamesebắt_đầu {
hằng danh_sách<văn_bản> raw ← ["1", "two", "3"]
làm {
lặp từ raw hằng item {
hằng số n ← item ↦ số
ghi_chú n
}
}
bắt err {
cảnh_báo err
}
}faber format --locale ar — Arabicبداية {
ثابت قائمة<نص> raw ← ["1", "two", "3"]
افعل {
كرر من raw ثابت item {
ثابت عدد n ← item ↦ عدد
اعرض n
}
}
التقط err {
نبه err
}
}faber format --locale hi — Hindiआरंभ {
स्थिर सूची<पाठ> raw ← ["1", "two", "3"]
करो {
दोहराओ सेवन raw स्थिर item {
स्थिर संख्या n ← item ↦ संख्या
दिखाओ n
}
}
पकड़ो err {
चेताओ err
}
}And so can a while loop:
faber format --locale en — English reader surfacemain {
var int i ← 0
do {
while i ≺ 3 {
i ← i + 1
if i ≡ 2 {
throw "halfway"
}
}
}
catch err {
warn err
}
}faber format --locale la — canonical Faberincipit {
varia numerus i ← 0
fac {
dum i ≺ 3 {
i ← i + 1
si i ≡ 2 {
iace "halfway"
}
}
}
cape err {
mone err
}
}faber format --locale th-TH — Thaiเริ่ม {
แปร จำนวน i ← 0
ทำ {
ขณะ i ≺ 3 {
i ← i + 1
ถ้า i ≡ 2 {
โยน "halfway"
}
}
}
จับ err {
เตือน err
}
}faber format --locale zh-Hans — Simplified Chinese入口 {
变量 整数 i ← 0
执行 {
当 i ≺ 3 {
i ← i + 1
如果 i ≡ 2 {
抛错 "halfway"
}
}
}
捕获 err {
警告 err
}
}faber format --locale zh-Hant — Traditional Chinese入口 {
變值 整數 i ← 0
執行 {
當 i ≺ 3 {
i ← i + 1
若 i ≡ 2 {
拋出 "halfway"
}
}
}
捕捉 err {
警告 err
}
}faber format --locale vi — Vietnamesebắt_đầu {
biến số i ← 0
làm {
trong_khi i ≺ 3 {
i ← i + 1
nếu i ≡ 2 {
ném "halfway"
}
}
}
bắt err {
cảnh_báo err
}
}faber format --locale ar — Arabicبداية {
متغير عدد i ← 0
افعل {
طالما i ≺ 3 {
i ← i + 1
إذا i ≡ 2 {
ارم "halfway"
}
}
}
التقط err {
نبه err
}
}faber format --locale hi — Hindiआरंभ {
चर संख्या i ← 0
करो {
जबतक i ≺ 3 {
i ← i + 1
यदि i ≡ 2 {
इधरफेंको "halfway"
}
}
}
पकड़ो err {
चेताओ err
}
}The handler belongs to the construct it follows. There is no separate try
keyword to wrap things in — do is simply the bare block form for when you
want a handler and have no other statement to hang it on.
Failing without a message#
A function that declares ⇥ and does not catch propagates automatically —
callers must deal with it or declare their own channel.
faber format --locale en — English reader surfacefn parse(string raw) → int ⇥ string {
if raw ≡ "" {
throw "empty input"
}
return raw ↦ int ⇥ 0
}
fn duplum(string raw) → int ⇥ string {
return parse(raw) * 2
}
main {
do {
print duplum("21")
}
catch err {
warn err
}
}faber format --locale la — canonical Faberfunctio parse(textus raw) → numerus ⇥ textus {
si raw ≡ "" {
iace "empty input"
}
redde raw ↦ numerus ⇥ 0
}
functio duplum(textus raw) → numerus ⇥ textus {
redde parse(raw) * 2
}
incipit {
fac {
nota duplum("21")
}
cape err {
mone err
}
}faber format --locale th-TH — Thaiฟังก์ชัน parse(ข้อความ raw) → จำนวน ⇥ ข้อความ {
ถ้า raw ≡ "" {
โยน "empty input"
}
คืน raw ↦ จำนวน ⇥ 0
}
ฟังก์ชัน duplum(ข้อความ raw) → จำนวน ⇥ ข้อความ {
คืน parse(raw) * 2
}
เริ่ม {
ทำ {
บันทึก duplum("21")
}
จับ err {
เตือน err
}
}faber format --locale zh-Hans — Simplified Chinese函数 parse(文本 raw) → 整数 ⇥ 文本 {
如果 raw ≡ "" {
抛错 "empty input"
}
返回 raw ↦ 整数 ⇥ 0
}
函数 duplum(文本 raw) → 整数 ⇥ 文本 {
返回 parse(raw) * 2
}
入口 {
执行 {
显示 duplum("21")
}
捕获 err {
警告 err
}
}faber format --locale zh-Hant — Traditional Chinese函式 parse(文字 raw) → 整數 ⇥ 文字 {
若 raw ≡ "" {
拋出 "empty input"
}
傳回 raw ↦ 整數 ⇥ 0
}
函式 duplum(文字 raw) → 整數 ⇥ 文字 {
傳回 parse(raw) * 2
}
入口 {
執行 {
註記 duplum("21")
}
捕捉 err {
警告 err
}
}faber format --locale vi — Vietnamesehàm parse(văn_bản raw) → số ⇥ văn_bản {
nếu raw ≡ "" {
ném "empty input"
}
trả raw ↦ số ⇥ 0
}
hàm duplum(văn_bản raw) → số ⇥ văn_bản {
trả parse(raw) * 2
}
bắt_đầu {
làm {
ghi_chú duplum("21")
}
bắt err {
cảnh_báo err
}
}faber format --locale ar — Arabicدالة parse(نص raw) → عدد ⇥ نص {
إذا raw ≡ "" {
ارم "empty input"
}
أعد raw ↦ عدد ⇥ 0
}
دالة duplum(نص raw) → عدد ⇥ نص {
أعد parse(raw) * 2
}
بداية {
افعل {
اعرض duplum("21")
}
التقط err {
نبه err
}
}faber format --locale hi — Hindiफलन parse(पाठ raw) → संख्या ⇥ पाठ {
यदि raw ≡ "" {
इधरफेंको "empty input"
}
लौटाओ raw ↦ संख्या ⇥ 0
}
फलन duplum(पाठ raw) → संख्या ⇥ पाठ {
लौटाओ parse(raw) * 2
}
आरंभ {
करो {
दिखाओ duplum("21")
}
पकड़ो err {
चेताओ err
}
}duplum never mentions failure in its body. It declares the channel and lets
parse's failure travel through.
Errors as a parameter#
errata marks a parameter that carries an error value, for functions written
to receive one rather than produce it.
faber format --locale en — English reader surfacefn logga(string context) → void {
warn context
}faber format --locale la — canonical Faberfunctio logga(textus context) → vacuum {
mone context
}faber format --locale th-TH — Thaiฟังก์ชัน logga(ข้อความ context) → เปล่า {
เตือน context
}faber format --locale zh-Hans — Simplified Chinese函数 logga(文本 context) → 无值 {
警告 context
}faber format --locale zh-Hant — Traditional Chinese函式 logga(文字 context) → 空值 {
警告 context
}faber format --locale vi — Vietnamesehàm logga(văn_bản context) → trống {
cảnh_báo context
}faber format --locale ar — Arabicدالة logga(نص context) → فراغ {
نبه context
}faber format --locale hi — Hindiफलन logga(पाठ context) → रिक्त {
चेताओ context
}Related: Testing ·
Conversions for ⇥ in its other role, as
conversion recovery · Errors and testing for the full
treatment.