Skip to content

Zig tracking issue #10

@eestrada

Description

@eestrada

A Zig tracking issue for blockers and wishes, as per this wiki page.

There are no hard blockers for Havarti porting to Zig from Go at this point. They will be added here if/when they show up.

Here are some wishes below.

1. Something like an okdefer keyword

Currently the only frustrating imbalance is the lack of something like an okdefer keyword. For database transactions in particular this would be useful. For example:

// All setup and teardown is clustered in one place and intent is clear: 
// * on error rollback the transaction 
// * on success commit the transaction
var tx = try db.Transaction.begin();
errdefer tx.rollback();
okdefer tx.commit();

// Do all work the afterward

Alternatives

Do nothing and hope people remember to Do the Right Thing ™️ when dealing with early returns

Example:

pub fn doWork(db: DatabaseType) !void {
    var tx = try db.Transaction.begin();
    errdefer ts.rollback();

    // do some work

    // Check for early return
    if(earlyReturnCondition()) {
        // Don't forget to commit!
        tx.commit()
        return;
    }

    // do some more work

    if(otherEarlyReturnCondition()) {
        // Don't forget to commit!
        tx.commit()
        return;
    }

    // do yet more work

    tx.commit();
}
Reasons against

This is hoping the developer isn't forgetful. It seems to be antithetical to Zig's philosophy of making it easy to do the right thing in this circumstance.

Using another function

Example:

fn innerWork(db: DatabaseType) !void {
    // do work here
}

pub fn outerWork(db: DatabaseType) !void {
    var tx = try db.Transaction.begin();
    errdefer tx.rollback();
    try innerWork(db);
    tx.commit();
}
Reasons against

This is clunky and doesn't make intent as clear. Another dev may add more code in the outerWork function without realizing that all work should be in the innerWork function. Code comments would help, but having an okdefer keyword makes intent unmistakably clear. This is clearly better than just hoping people remember to Do The Right Thing, but it still isn't ideal.

Use regular defer and a tracking variable

Example:

var tx = try db.Transaction.begin();
var txok = true;
defer if (txok) tx.commit();
errdefer tx.rollback();
errdefer txok = false;

// Do all work the afterward
Reasons against

Syntax it clunky, pollutes the namespace with extra variables, and makes the setup/teardown order dependent. Whereas errdefer and okdefer can be specified in any order and work just fine, this approach requires errdefer statements be defined last so that they are executed before the defer statements used for successful exit (since defered expressions execute in reverse order). This at least bundles all setup/teardown together. But it could easily break things without care.

Background

There was a prior proposal similar to this, but it seemed to be closed without being implemented. My guess is that it was mostly because the proposal didn't give a strong use case. However, Havarti uses database transactions all over the place. Being able to use this as a pattern would make code vastly cleaner and clearer; I think there is a strong use case with DB transaction rollback versus commit.

Metadata

Metadata

Assignees

No one assigned

    Labels

    enhancementNew feature or request

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions