4 ms·
No I'm quite aware of this. It's a restricted, implicit variant of it. But not also that it's not the type but the binding, which makes it slightly different fr
by lerno 5y ago
No I'm quite aware of this. It's a restricted, implicit variant of it. But not also that it's not the type but the binding, which makes it slightly different from using a `Result`.
- mananaysiempre 5y agoHm. 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.)
- lerno 5y agoWhat 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!