aboutsummaryrefslogtreecommitdiffhomepage
path: root/notes/error_object.txt
blob: 8e4ba1a0447ed6562c6cc9a4268018e5070d7826 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62

Error object
============

Error codes do not tell the full story.
For example, in pseudo-code:

    open_config_file()
    open_file(input_file, .read)
    open_file(output_file, .write)

The error "file not found" would not have enough information in this case.

Also:
If more additional information can be stored, it might be worth to skip
support for "ref or errorcode" types, and store the error code together
with the error object.

Solution 1: "error object" reference in the arena
-------------------------------------------------
Have an "error info" object in the arena base, similar to errno,
but instead of a thread-local integer, it is a arena-local struct.
This struct contains the "error object" (e.g. the filename for "file not
found" errors) as well as a function pointer to a formatter function,
for formatting the error to a string.

When an error occurs, the callee sets the information in the errinfo
structure and returns null/false/an error code. The caller can then
handle the error, or it can throw an exception. If it throws an exception,
then the error handler can use the error info object to show a good and
user friendly error message.

At startup, the errinfo should be initialized by the runtime:
    errobject = none
    format_message = format_noerror

Something like this:

    type ArenaBase = struct {
        ...
        ErrorInfo<?> errinfo
        ...
    }

    type ErrorInfo<enum E, ref T> = struct {
        # maybe this should contain the error code as well? in that case, error codes would be returned here.
        #enum E code
        ?ref T errobject # does not have to be a "full" object. it can be a filename, URL, or similar
        func format_message<enum E, ref T>(arena, enum E code, ?ref T obj, ref Locale locale, ?ref var LocaleMessageInfo lmi) -> string
                lifetime obj >= arena
                lifetime arena >= lmi
        # lmi holds locale-specific information
        # alternatively:
        func format_message<T>(arena, enum E code, ?ref T errobj, ref Locale locale) -> ref LocalizedMessage
                lifetime errobj >= arena
        # alternatively
        func format(this, arena, ref ErrorFormatter ef, enum E code, ?ref T errobj) -> ref LocalizedMessage
                lifetime errobj >= arena
    }

    func arena var ErrorFormatter.wants_error_code() -> bool    # e.g. file_not_found... or maybe just in English: "file not found"  FIXME can the error codes be passed as enums?
    func arena var ErrorFormatter.wants_error_object() -> bool  # e.g. filename
    func arena var ErrorFormatter.format(?string code, ?string object, ?string other_object) -> string      # other_object is only meaningful for operations/errors that contain multiple objects (e.g. "rename", "add to", "remove from", "compare", etc.)