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 convert --to en — English reader surfacefn divide(int a, int b) → int ⇥ string {
if b ≡ 0 {
throw "division by zero"
}
return a / b
}faber convert --to la — canonical Faberfunctio divide(numerus a, numerus b) → numerus ⇥ textus {
si b ≡ 0 {
iace "division by zero"
}
redde a / b
}faber convert --to th-TH — Thaiฟังก์ชัน divide(จำนวน a, จำนวน b) → จำนวน ⇥ ข้อความ {
ถ้า b ≡ 0 {
โยน "division by zero"
}
คืน a / b
}faber convert --to zh-Hans — Simplified Chinese函数 divide(整数 a, 整数 b) → 整数 ⇥ 文本 {
如果 b ≡ 0 {
抛错 "division by zero"
}
返回 a / b
}faber convert --to zh-Hant — Traditional Chinese函式 divide(整數 a, 整數 b) → 整數 ⇥ 文字 {
若 b ≡ 0 {
拋出 "division by zero"
}
傳回 a / b
}faber convert --to 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 convert --to ar — Arabicدالة divide(عدد a, عدد b) → عدد ⇥ نص {
إذا b ≡ 0 {
ارم "division by zero"
}
أعد a / b
}faber convert --to hi — Hindiफलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
यदि b ≡ 0 {
इधरफेंको "division by zero"
}
लौटाओ a / b
}Read it as: returns a number, or fails with a string. 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.
throw sends a value down the error channel. It is not return: it exits by the
other route.
Guards: require / reject#
A guard pairs the condition and the throw in one statement. require
(English require) throws when the condition fails; reject (English
reject) throws when the condition holds:
faber convert --to en — English reader surfacefn divide(int a, int b) → int ⇥ string {
require b ≠ 0 throw "division by zero"
return a / b
}
fn exigePositivum(int value) → int ⇥ string {
reject value ≺ 0 throw "negative value"
return value
}faber convert --to la — canonical Faberfunctio divide(numerus a, numerus b) → numerus ⇥ textus {
requirit b ≠ 0 iace "division by zero"
redde a / b
}
functio exigePositivum(numerus value) → numerus ⇥ textus {
reice value ≺ 0 iace "negative value"
redde value
}faber convert --to th-TH — Thaiฟังก์ชัน divide(จํานวน a, จํานวน b) → จํานวน ⇥ ข้อความ {
ต้องการ b ≠ 0 โยน "division by zero"
คืน a / b
}
ฟังก์ชัน exigePositivum(จํานวน value) → จํานวน ⇥ ข้อความ {
ปฏิเสธ value ≺ 0 โยน "negative value"
คืน value
}faber convert --to zh-Hans — Simplified Chinese函数 divide(整数 a, 整数 b) → 整数 ⇥ 文本 {
需求 b ≠ 0 抛错 "division by zero"
返回 a / b
}
函数 exigePositivum(整数 value) → 整数 ⇥ 文本 {
拒绝 value ≺ 0 抛错 "negative value"
返回 value
}faber convert --to zh-Hant — Traditional Chinese函式 divide(整數 a, 整數 b) → 整數 ⇥ 文字 {
需要 b ≠ 0 拋出 "division by zero"
傳回 a / b
}
函式 exigePositivum(整數 value) → 整數 ⇥ 文字 {
拒絕 value ≺ 0 拋出 "negative value"
傳回 value
}faber convert --to vi — Vietnamesehàm divide(số a, số b) → số ⇥ văn_bản {
yêu_cầu b ≠ 0 ném "division by zero"
trả a / b
}
hàm exigePositivum(số value) → số ⇥ văn_bản {
từ_chối value ≺ 0 ném "negative value"
trả value
}faber convert --to ar — Arabicدالة divide(عدد a, عدد b) → عدد ⇥ نص {
يتطلب b ≠ 0 ارم "division by zero"
أعد a / b
}
دالة exigePositivum(عدد value) → عدد ⇥ نص {
يرفض value ≺ 0 ارم "negative value"
أعد value
}faber convert --to hi — Hindiफलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
आवश्यक b ≠ 0 इधरफेंको "division by zero"
लौटाओ a / b
}
फलन exigePositivum(संख्या value) → संख्या ⇥ पाठ {
अस्वीकार value ≺ 0 इधरफेंको "negative value"
लौटाओ value
}Like throw itself, guards need the function to declare a ⇥ channel.
Catching#
catch binds whatever came down the error channel.
faber convert --to 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 convert --to 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 convert --to 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 convert --to 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 convert --to 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 convert --to 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 convert --to 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 convert --to 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 convert --to en — English reader surfacemain {
const list<string> raw ← ["1", "two", "3"]
for from raw const item {
const int n ← item ↦ int
print n
} catch err {
warn err
}
}faber convert --to la — canonical Faberincipit {
fixum lista<textus> raw ← ["1", "two", "3"]
itera ex raw fixum item {
fixum numerus n ← item ↦ numerus
nota n
} cape err {
mone err
}
}faber convert --to th-TH — Thaiเริ่ม {
คงที่ รายการ<ข้อความ> raw ← ["1", "two", "3"]
วน ออก raw คงที่ item {
คงที่ จํานวน n ← item ↦ จํานวน
บันทึก n
} จับ err {
เตือน err
}
}faber convert --to zh-Hans — Simplified Chinese入口 {
常量 列表<文本> raw ← ["1", "two", "3"]
遍历 取自 raw 常量 item {
常量 整数 n ← item ↦ 整数
显示 n
} 捕获 err {
警告 err
}
}faber convert --to zh-Hant — Traditional Chinese入口 {
定值 列表<文字> raw ← ["1", "two", "3"]
遍歷 取自 raw 定值 item {
定值 整數 n ← item ↦ 整數
註記 n
} 捕捉 err {
警告 err
}
}faber convert --to vi — Vietnamesebắt_đầu {
hằng danh_sách<văn_bản> raw ← ["1", "two", "3"]
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 convert --to ar — Arabicبداية {
ثابت قائمة<نص> raw ← ["1", "two", "3"]
كرر من raw ثابت item {
ثابت عدد n ← item ↦ عدد
اعرض n
} التقط err {
نبه err
}
}faber convert --to hi — Hindiआरंभ {
स्थिर सूची<पाठ> raw ← ["1", "two", "3"]
दोहराओ सेवन raw स्थिर item {
स्थिर संख्या n ← item ↦ संख्या
दिखाओ n
} पकड़ो err {
चेताओ err
}
}And so can a while loop:
faber convert --to en — English reader surfacemain {
var int i ← 0
while i ≺ 3 {
i ← i + 1
if i ≡ 2 {
throw "halfway"
}
} catch err {
warn err
}
}faber convert --to la — canonical Faberincipit {
varia numerus i ← 0
dum i ≺ 3 {
i ← i + 1
si i ≡ 2 {
iace "halfway"
}
} cape err {
mone err
}
}faber convert --to th-TH — Thaiเริ่ม {
แปร จํานวน i ← 0
ขณะ i ≺ 3 {
i ← i + 1
ถ้า i ≡ 2 {
โยน "halfway"
}
} จับ err {
เตือน err
}
}faber convert --to zh-Hans — Simplified Chinese入口 {
变量 整数 i ← 0
当 i ≺ 3 {
i ← i + 1
如果 i ≡ 2 {
抛错 "halfway"
}
} 捕获 err {
警告 err
}
}faber convert --to zh-Hant — Traditional Chinese入口 {
變值 整數 i ← 0
當 i ≺ 3 {
i ← i + 1
若 i ≡ 2 {
拋出 "halfway"
}
} 捕捉 err {
警告 err
}
}faber convert --to vi — Vietnamesebắt_đầu {
biến số i ← 0
trong_khi i ≺ 3 {
i ← i + 1
nếu i ≡ 2 {
ném "halfway"
}
} bắt err {
cảnh_báo err
}
}faber convert --to ar — Arabicبداية {
متغير عدد i ← 0
طالما i ≺ 3 {
i ← i + 1
إذا i ≡ 2 {
ارم "halfway"
}
} التقط err {
نبه err
}
}faber convert --to 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 convert --to 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 convert --to 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 convert --to th-TH — Thaiฟังก์ชัน parse(ข้อความ raw) → จํานวน ⇥ ข้อความ {
ถ้า raw ≡ "" {
โยน "empty input"
}
คืน raw ↦ จํานวน ⊥ 0
}
ฟังก์ชัน duplum(ข้อความ raw) → จํานวน ⇥ ข้อความ {
คืน parse(raw) * 2
}
เริ่ม {
ทำ {
บันทึก duplum("21")
}
จับ err {
เตือน err
}
}faber convert --to zh-Hans — Simplified Chinese函数 parse(文本 raw) → 整数 ⇥ 文本 {
如果 raw ≡ "" {
抛错 "empty input"
}
返回 raw ↦ 整数 ⊥ 0
}
函数 duplum(文本 raw) → 整数 ⇥ 文本 {
返回 parse(raw) * 2
}
入口 {
执行 {
显示 duplum("21")
}
捕获 err {
警告 err
}
}faber convert --to zh-Hant — Traditional Chinese函式 parse(文字 raw) → 整數 ⇥ 文字 {
若 raw ≡ "" {
拋出 "empty input"
}
傳回 raw ↦ 整數 ⊥ 0
}
函式 duplum(文字 raw) → 整數 ⇥ 文字 {
傳回 parse(raw) * 2
}
入口 {
執行 {
註記 duplum("21")
}
捕捉 err {
警告 err
}
}faber convert --to 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 convert --to ar — Arabicدالة parse(نص raw) → عدد ⇥ نص {
إذا raw ≡ "" {
ارم "empty input"
}
أعد raw ↦ عدد ⊥ 0
}
دالة duplum(نص raw) → عدد ⇥ نص {
أعد parse(raw) * 2
}
بداية {
افعل {
اعرض duplum("21")
}
التقط err {
نبه err
}
}faber convert --to 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#
A caught error is an ordinary value, so a function can receive one like any
other parameter. Declare the parameter with the error's type and pass the
catch binding straight in.
faber convert --to en — English reader surfacefn divide(int a, int b) → int ⇥ string {
if b ≡ 0 {
throw "division by zero"
}
return a / b
}
fn logga(string context, string err) → void {
warn context
warn err
}
main {
do {
print divide(1, 0)
}
catch err {
logga("divide", err)
}
}faber convert --to la — canonical Faberfunctio divide(numerus a, numerus b) → numerus ⇥ textus {
si b ≡ 0 {
iace "division by zero"
}
redde a / b
}
functio logga(textus context, textus err) → vacuum {
mone context
mone err
}
incipit {
fac {
nota divide(1, 0)
}
cape err {
logga("divide", err)
}
}faber convert --to th-TH — Thaiฟังก์ชัน divide(จํานวน a, จํานวน b) → จํานวน ⇥ ข้อความ {
ถ้า b ≡ 0 {
โยน "division by zero"
}
คืน a / b
}
ฟังก์ชัน logga(ข้อความ context, ข้อความ err) → เปล่า {
เตือน context
เตือน err
}
เริ่ม {
ทำ {
บันทึก divide(1, 0)
}
จับ err {
logga("divide", err)
}
}faber convert --to zh-Hans — Simplified Chinese函数 divide(整数 a, 整数 b) → 整数 ⇥ 文本 {
如果 b ≡ 0 {
抛错 "division by zero"
}
返回 a / b
}
函数 logga(文本 context, 文本 err) → 无值 {
警告 context
警告 err
}
入口 {
执行 {
显示 divide(1, 0)
}
捕获 err {
logga("divide", err)
}
}faber convert --to zh-Hant — Traditional Chinese函式 divide(整數 a, 整數 b) → 整數 ⇥ 文字 {
若 b ≡ 0 {
拋出 "division by zero"
}
傳回 a / b
}
函式 logga(文字 context, 文字 err) → 空值 {
警告 context
警告 err
}
入口 {
執行 {
註記 divide(1, 0)
}
捕捉 err {
logga("divide", err)
}
}faber convert --to 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 logga(văn_bản context, văn_bản err) → trống {
cảnh_báo context
cảnh_báo err
}
bắt_đầu {
làm {
ghi_chú divide(1, 0)
}
bắt err {
logga("divide", err)
}
}faber convert --to ar — Arabicدالة divide(عدد a, عدد b) → عدد ⇥ نص {
إذا b ≡ 0 {
ارم "division by zero"
}
أعد a / b
}
دالة logga(نص context, نص err) → فراغ {
نبه context
نبه err
}
بداية {
افعل {
اعرض divide(1, 0)
}
التقط err {
logga("divide", err)
}
}faber convert --to hi — Hindiफलन divide(संख्या a, संख्या b) → संख्या ⇥ पाठ {
यदि b ≡ 0 {
इधरफेंको "division by zero"
}
लौटाओ a / b
}
फलन logga(पाठ context, पाठ err) → रिक्त {
चेताओ context
चेताओ err
}
आरंभ {
करो {
दिखाओ divide(1, 0)
}
पकड़ो err {
logga("divide", err)
}
}There is no special parameter keyword for this. The legacy errors function
modifier is not how a function receives an error; use an ordinary parameter.
Related: Testing ·
Conversions for ⊥, the
conversion default · Errors and testing for the full
treatment.