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

I just can't get past the fact that Go doesn't have sum types. As someone who dabbles in category theory, it makes no sense to me that so many popular languages have product types but not their categorical dual. The lack of sum types leads to so many hacks and weird design patterns in the language, like returning two values when you only want the caller to read one of them (that is actually Go's error handling strategy!). To work around the limitations of not having sum types, Go has a "zero" value for every type so you can for example only set the fields relevant to your particular use case, and just hope that no one reads the fields you didn't set.

The problem is that sometimes the zero value is valid, but not special in any way and doesn't make sense as the default. Go has arbitrarily decided that one particular value is special without your blessing or the ability to override it. This leads to bugs in which the zero value shows up in places where you don't expect it, simply because there is some code which doesn't explicitly set it. That's a very easy mistake to make, which makes writing Go an error prone activity.

I shudder to think that there's probably some Go program that deals with money, and a user's balance might be cleared to zero simply because some operation forgot to explicitly set it in some struct.

In order to implement "optional" fields in Go where you want to distinguish between zero (a valid value) and none (a missing value), the common solution is to either put the integer behind a pointer (which can be null) or use some "sentinel" value like -1 to indicate that the value is missing (as long as that sentinel value isn't actually valid in the domain of discourse). These are terrible hacks, but exactly what you'd expect from programmers who spent the majority of their careers writing C.

This design also leads to another kind of issue: sometimes you don't want people to be able to construct values of a particular type without going through a constructor which ensures the relevant invariants hold. This concept ("smart constructors") is widely used in other programming languages, but it's impossible in Go because Go allows anyone to construct an inhabitant of any type simply by declaring a variable of that type.

A simple example of that kind of issue is pointers: in (safe) Rust, references are guaranteed to be non-null, and you use sum types to implement optionality. This is great because you can always dereference a reference and not worry about handling the null case. In Go, all pointer types have that nasty zero value (null), and there's nothing you can do about it. The billion dollar mistake.

I like the fact that Go encourages simplicity, and for the most part the language is fine. But I'm convinced that having every type be pointed rather than supporting proper sum types is actually more complex in terms of the implications it has on writing and reasoning about code. They have mistaken minimality for simplicity.



> These are terrible hacks, but exactly what you'd expect from programmers who spent the majority of their careers writing C.

As an embedded firmware guy, I'll try not to be offended by that line :) I agree with you, though. C is a really good language when you consider its original purpose and the time period in which it was created. Ignoring 50 years of progress in type theory/category theory in the name of "simplicity" is inexcusable.


> but exactly what you'd expect from programmers who spent the majority of their careers writing C

Writing C is an understatement given that Go and C were created by the same person (with help, of course).


Edge case. Maybe make a library to solve this?


If it causes errors in monetary calculations that can hardly be described as an edge case.




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

Search: