Other places where Go relies on every type having a zero value: // Making slices with non-zero length. s := make([]*int, 10)
// Reslicing a slice beyond its length. s := make([]*int, 0, 10)[:10] // Eliding fields from a composite literal. p := struct { x: int; y: *int } { x: 5 } s := []*int { 10: new(int) } // Initializing an array programmatically. var arr [10]*int for i := range arr { ... } // Accessing a non-existent map entry. v := m["non existent"] // Reading from a closed channel. v := <-ch // Comma-ok. // Without zero values, the type of `v` is in each case // something like `ok ? *int : uninitialized`. v, ok := m["string"] v, ok := i.(*int) v, ok := <-ch On Tue, Aug 22, 2017 at 8:59 AM <gurpar...@gmail.com> wrote: > I would like to echo on Tong Sun's suggestion here. I know his isn't an > "experience report" per se, but a suggestion worth building on, for those > who're wishful of optionals in Go. > > The case mentioned might be immediately solvable by just using a pointer > to the variable, which gives you the ability to assign nil (json null) to > it. However, *T is *not* syntactic sugar for Optional<T>. Pointers come > across as "just as good as optionals" when needed because we don't have > another [built-in] option. Not to mention, pointers have more than > nil-assignability to them. > > I understand that we can just write a generic generator for Optional<T> > for whatever type we want an optional wrapper for. This is something I've > always done when absolutely needed (most of the time with proto3 Protobuf). > > func main() { > msg := pboptional.NewString() > > fmt.Println("msg:", msg). // => msg: nil > > msg.From("hello world") > > fmt.Println("msg:", msg) // => msg: Optional("hello world") > > if msg, ok := msg.Unwrap(); ok { > // some > fmt.Println("msg:", msg) // => msg: hello world > } else { > // none > fmt.Println("msg is nil") > } > } > > There are obvious advantages to using optionals, including safely defining > variable. However, on the contrary, Go is currently, and by-design so, not > in the best shape to adopt optional types. For optionals to be a viable in > core, non-optionals would have to (?) guarantee a value (and not just > assumed zero-value when left uninitialized). This is for the compiler to > deliver the type-safety promise of optionals *and* non-optionals. In > other words, it means that we would have to not allow uninitialized types > to be zero-value. I mean, what good is supporting optional types, if the > non-optionals don't require you to set their values? > > Consider this currently valid Go code: > > func getAge() (int, error) { > var age int > return age, errors.New("ERR") // age is assumed zero-value > } > > func main() { > age, err := getAge() // => 0, ERR > } > > With optionals implemented (how I'm imagining), this would become: > > // uninitialized non-optional should not compile > // i.e. don't assume zero-value > func getAge() (int, error) { > var age int > return age, errors.New("ERR") // => compile error: variable age is > not initialized > } > > // this should work instead > func getAge() (int?, error) { > var age int? > return nil, errors.New("ERR") > } > > func main() { > age, err := getAge() // => Optional(nil), ERR > } > > But every method that also returns an error, should not necessarily have > an accompanied optional type, like `(int?, error)`. There's so much in Go > that can be nil (or nil like zero-values), and isn't necessarily fit to be > considered optional, like nil interfaces and pointers. > > We're also going to have to reconsider the phrase "errors are just values" > if we want to pair non-optional types with error in the return types. Take > the following suggestion (inspired from Swift): > > func getAge() (int, throws error) { > var age int > throw errors.New("ERR") > // we're not returning anything and it compiles > // i.e. throw *is* return but only for error > } > > func main() { > age := try getAge() // => panic("ERR") > } > > func main() { > // although getAge() returns a non-optional, it > // gets is automatically wrapped in an optional > // when using `try?`. > // > // basically we're trading error for nil value. > age := try? getAge() // => Optional(nil) > } > > func main() { > // this is the graceful way to get non-optional result > // and handle error, if any. > try { > age := getAge() > } catch error { > fmt.Println(err.Error()) // => ERR > } > } > > Therefore, if considered, optionals would be a *huge* undertaking to > implement (and practice) in Go source, while also delivering the promise > optionals bring. > > Let me know if you have a better syntax/suggestion than try catch blocks > (for returning only an error; no zero-values for non-optionals). > > I think an ideal first step would be the community blessing and adopting > en masse some Optional<T> "generator". Second step would be to vouch for > generics with this use case. And then implement an actual generic like > `type Optional<T> struct { Value T; HasValue bool }`. And then perhaps, as > the fourth or so step, we may shape our coding practices to better > understand how all this could be practiced in Go source itself. > > -- > Gurpartap Singh > https://twitter.com/Gurpartap > > On Saturday, August 19, 2017 at 8:35:34 PM UTC+5:30, Tong Sun wrote: >> >> Suggesting C# type syntax like "int*?*" so as to take nil as valid >> value. >> >> Currently: >> >> var i int >> i = nil >> >> will give: >> >> cannot use nil as type int in assignment >> >> However, more and more people are using json to transport data, and there >> will be times that json may be invalid. I.e., the "int" type has 'null' as >> input. >> >> This is causing tremendous problems for me so far, as I have to jump over >> the hoops to deal with them. >> In C#, just by adding a "?" to the end of the type solves the problem. >> >> Please consider. >> >> >> >> -- > You received this message because you are subscribed to the Google Groups > "golang-nuts" group. > To unsubscribe from this group and stop receiving emails from it, send an > email to golang-nuts+unsubscr...@googlegroups.com. > For more options, visit https://groups.google.com/d/optout. > -- You received this message because you are subscribed to the Google Groups "golang-nuts" group. To unsubscribe from this group and stop receiving emails from it, send an email to golang-nuts+unsubscr...@googlegroups.com. For more options, visit https://groups.google.com/d/optout.