Hacker Newsnew | past | comments | ask | show | jobs | submitlogin

Hm. OK. I tried writing a response several times but I still feel confused. Can you explain what you mean by “not the type but the binding”? Note that I know the Haskell but not the Rust (guessing from the “Result” name) way of working in this style.

(Not necessarily relevant or correct thoughts:

- Your language still seems to mark potentially-failed values in the type system, even if it writes them T! not Either Error T or Result<Error, T>;

- The way Haskell’s do-notation [apparently implemented as a macro package in Rust] is centred around name binding seems very close to what you’re doing, although it [being monadic, not applicative] insists on sequencing everything, so fails the whole block immediately once an error value occurs;

- Of course, transparently morphing a T-or-error into a T after a check for an error either needs to be built into the language or requires a much stronger type system; Haskell circumvents this by saying that x <- ... either gives you a genuine T or returns failure immediately, which is indeed not quite what you’re doing.)



What I mean by saying "it's a binding" is that it is a property of the variable (or return channel of a function) rather than a real sum type. Consequently it does not participate in any type conversions and you cannot pass something "of type int!" because the type does not exist.

Here is an example:

    int! x = ...
    int*! y = &x;
    int**! z = &y;

    // If it had been a type then
    // int!* y = &x;
    // int!** z = &y;

    // int*! y = &x;
    // means 
    // int*! y = "if x is err" ? "error of x" 
    //                         : "the address holding the int of x"
This also means that `int!` cannot ever be a parameter, nor a type of a member inside of a struct or union.

The underlying implementation is basically that for a variable `int! x` what is actually stored is:

    // int! x;
    int x$real;
    ErrCode x$err;

    // int*! y;
    int* y$real;
    ErrCode y$err;

    // y = &x;
    if (x$err) {
      y$err = x$err;
    } else {
      y$real = &x$real;
    }

    int z;
    // y = &z;
    y$err = 0;
    y$real = &x;

The semantics resulting from this is different from if `int!` had been something like

    struct IntErr { 
      bool is_err_tag;
      union {
        int value;
        ErrCode error;
      };
    };
Which is what a Result based solution would work like. In such a solution:

    int! x ... ;
    int!* y = &x; // Ok
    int z = ...
    y = &z; // <- Type error!




Consider applying for YC's Summer 2026 batch! Applications are open till May 4

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: