News for hackers. Stuff that matters.
Re:Go 1.18 Beta 1 is available, with generics by sacado2 on Wednesday December 15, 2021 @09:34AM (#29566454)
Not as simple as it seems. For instance, what is the zero value of a sum type? Let's say, the zero value of a Result<int, error>?
Re:Go 1.18 Beta 1 is available, with generics by kortex on Wednesday December 15, 2021 @09:53AM (#29566711)
Perfect example of a caveat to "without sacrifice". For context, go really cares about having "zero values" - every initialized variable of some type must have a zero value.

The zero of Error is nil, so logically this would be Result(0, nil). But what do you set the internal state? It's not Ok, cause that int isn't used, and it's not Err either.

Option would work fine though and it would be amazing to map over options instead of nil checks.

I think you'd need to build Result on top of Option, it's naturally kind of ternary - "I have value" "I have error" "idk", either internally or externally.

What might be awesome would be if the Error were a slice type, nil would be "uninitialized" and empty slice means "initialized". still not...pleasant.

Re:Go 1.18 Beta 1 is available, with generics by DylanSp on Wednesday December 15, 2021 @11:00AM (#29567805)
Zero values are definitely an issue, and it'd be hard to get rid of them while sticking to Go's imperative/statement-based style. Still, it'd nice to use an Option type instead of pointers.
Re:Go 1.18 Beta 1 is available, with generics by Lev1a on Wednesday December 15, 2021 @10:01AM (#29566820)
IIRC in Rust it has to be either of the Ok or Err variants and the enclosed type can then provide its own "zero value" via the standard library "Default" [0] trait or your own implementation for the particular type. That trait is also implemented not for "Result" but for "Option" giving it a default value of "None".

[0]: https://doc.rust-lang.org/std/default/trait.Default.html

Re:Go 1.18 Beta 1 is available, with generics by sacado2 on Wednesday December 15, 2021 @10:30AM (#29567238)
Yes, for Option the default value is quite obvious. I'm talking about Result, because it's the second best-known sum type, and it doesn't have an obvious default value.
Re:Go 1.18 Beta 1 is available, with generics by Lev1a on Wednesday December 15, 2021 @05:58PM (#29572648)
Bindings in Rust have to initialized with an explicit value if the first use comes before the first modification/assignment otherwise [0] you get an error message with error E0381 [1]. Even if that explicit assignment is just through the use of the type's default method [2], if available.

Since it's implemented for Option<T> you can do it the same way [3] for that, but that's not available for Result<T,U> since the semantics are different from Option which is basically just Rust's alternative for 'null'/'nil' (but verifiable by the compiler).

Thus you'd have to choose what variant of the enum you want to have at initialization, after which you can use the Default implementation of the enclosed type, if available (and so on, if there are more nested types).

Though honestly I can't recall using the kind of pattern in Rust that would "need" something like that. Through the handling of code blocks as expressions, early returns etc. you for example don't need to initialize a variable before having an if-/match-/for-/while-/etc. block, you can simply use that block as an expression on the right side of the assignment [4].

[0]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

[1]: https://doc.rust-lang.org/stable/error-index.html#E0381

[2]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

[3]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

[4]: https://play.rust-lang.org/?version=stable&mode=debug&editio...

Re:Go 1.18 Beta 1 is available, with generics by foldr on Friday December 17, 2021 @05:36AM (#29590391)
In Go, every type has a sensible built-in zero value. In Rust there is no need to worry about what the 'default' value of a Result type should be. So choosing a sensible default value for result would be a problem in Go (but not in Rust).
Re:Go 1.18 Beta 1 is available, with generics by lucian1900 on Wednesday December 15, 2021 @10:21AM (#29567107)
The zero value of a sum type can be the zero value of the first (or chosen) constituent. In this case, it could be Result<0>.
Re:Go 1.18 Beta 1 is available, with generics by sacado2 on Wednesday December 15, 2021 @10:29AM (#29567206)
I'm not sure that would be any better, in practice, than doing return 0, nil.
Re:Go 1.18 Beta 1 is available, with generics by lucian1900 on Wednesday December 15, 2021 @11:42AM (#29568317)
It would allow functions to be treated generically as returning error-able types. Since some functions even return 3 arguments where the third is the error, this isn't possible today.

It would also allow defer-like syntax to be used on the value a function returns, to return early from the calling function. Rust's ? is an excellent example of this, allowing explicit delegation of error handling that is still very lightweight syntactically.

Re:Go 1.18 Beta 1 is available, with generics by kortex on Wednesday December 15, 2021 @04:37PM (#29571936)
Function composition becomes a lot easier with Result/Option, because you can write functions in terms of assuming a "good" value (not nil/err or otherwise "bad") and then map over it. Or if we really wanna be fancy, flatmap/bind over it.

Foo, err requires either that all receiving functions accept (foo, err), or manually nil-checking at every stage.

Try/catch is the least composable, because deeper error types can "jump out" from any layer. Which means you have to keep wrapping catches, until you hit some base layer you can recover from. You get stack traces, but you lose type information along the way.

Sum (result) and product (foo, nil) types preserve type information. Meaning you can operate more generically over it. Meaning less code duplication.