Skip to content

proposal: Go 2: error handling by template functions #57822

Closed as not planned
Closed as not planned
@gohryt

Description

@gohryt

Author

Consider myself as intermediate go developer.
Experience: 2 years in production with go.
Other language experience: the most experience is in Js, tried many interesting things from LLVM IR to Nim and Odin.

Related proposals

Has this been proposed before? Variations have been proposed, this is discussed in the proposal.
Affect error handling: yes

Would this change make Go easier or harder to learn, and why?

This will make go harder by one middle-sized manual page. This will not be mandatory-to-use.

Proposal

Updated by comments at 19.01.23

Add a new "function" type template, special expression type for code blocks and inline function for expression insertion to template. As example

template orPanic(err error, log expression) {
    if err != nil {
        inline(log)
        panic(err)
    }
}

func main() {
    file, err := os.Open(filename)
    orPanic(err, { log.Println(err) })
    
    _, err = file.WriteString("example string")
    orPanic(err, { log.Println(err) })
    
    fmt.Println("string wrote")
}

should work as

func main() {
    file, err := os.Open(filename)
    if err != nil {
        log.Println(err)
        panic(err)
    }
    _, err = file.WriteString("example string")
    if err != nil {
        log.Println(err)
        panic(err)
    }
    println("string wrote")
}

The most important difference between func and template is that func share variables with template, and template is only a template of actions to insert to func.

It seems like universal try should be added to builtin library

template try(err error, catch expression) {
    if err != nil {
        inline(catch) 
    }
}

Why not use special keywords like try, catch and others?

The first reason is my personal reason - I wrote this sentence after monthly reading of other proposals on this topic which make me unhappy.
I selected Go as my primary language because of it's simplicity and human readability and i think new keywords will make it Java.

The second reason is that error handling problem is not error handling problem at all, it's a problem of template code which enrage developers. Now it's about errors, next we'll find some old-new places needs in template code problem solving.

Backward compatibility:

Full because no any go program in world use template keyword.

Example code:

func OnRequest(response http.ResponseWriter, request *http.Request) {  
    onError := template(err error, status int) {
        if err != nil {
            response.WriteHeader(status)
            return
        }
    }

    ...

    onError(json.NewDecoder(req.Body).Decode(...), http.StatusBadRequest)

    ...
}

should work as

func OnRequest(response http.ResponseWriter, request *http.Request) { 
    ...

    err := json.NewDecoder(req.Body).Decode(...)
    if err != nil {
        response.WriteHeader(http.StatusBadRequest)
        return
    }

    ...
}
func main() {
    _, err := os.Open(...)
    try(err, { return }) // universal try from builtin example (above) usage
}
func ShouldReturn() (*Example, err) {
    err := ...
    try(err, { return nil, err }) // universal try from builtin example (above) usage
}

should work as

func main() {
    _, err := os.Open(...)
    if err != nil {
        return
    }
}
func ShouldReturn() (*Example, err) {
    err := ...
    if err != nil {
        return nil, err
    }
}

Cost of this proposal:

Tools to rework: compiler, vet, gopls
Compile time cost: grows with the size of the project, seems like generics cost
Runtime cost: no cost

Possible implementation:

The most stupid is read code for template and insert it on the next read, but it's not a go way.
I tried to write prototype as preprocessor but didn't finish it.

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions