>First, it's often possible for the function to return a meaningful value even in an error case

Create a type that explicitly stores this information. The return type can hold the (error message and a value) OR (just a value). This type expression is a more accurate description of what's really going on. Whichever way you want to represent the product type it's not isomorphic to the actual intended result that the function should return. A sum type can represent the return value of the sentence below while GO cannot:

"A function that returns (a value) OR an (error with a value)"

This is the true intention of the function you described.

>Second, it's often possible to return a sensible 'null' value together with an error which can be handled correctly without checking the error value. (A map lookup is the obvious example of this.) This simplifies logic in some places.

But opens up the possibility of a runtime error if you fail to check for it. Historically there are tons of functions in C, C++ or javascript that use null to represent an error and it is self quoted to be the greatest mistake ever made by the creator of null. No language needs a null.

>Using sum types for errors in Go wouldn't actually work very well unless you fundamentally changed other aspects of the language. You'd need pattern matching....

Using product types to represent errors has already changed the nature of GO in a very hacky way.

Only Functions in GO can return tuples and the concept of the tuple can never be used anywhere else. You cannot save a variable as a tuple, you cannot pass a tuple as an argument. You can only return a tuple then instantly unroll it. It's an arbitrary hacky feature obviously made to support error values.

It would be better to have an arbitrary pattern matching feature... this makes more sense then arbitrary tuples returned from functions.

>a whole bunch of generic higher order functions for manipulating option/result types, etc. etc.

Actually no you don't. The fact that go functions return tuples with errors, does this mean that higher order functions need to handle tuples? No! not at all. In fact go explicitly eliminates support for this... The tuples in GO need to be unrolled into their constituent types before they can be used in any other function. The same concept can be applied to Option types. You have to unroll the value and explicitly handle either individual type. You do not ever need a higher order function that accepts the Option type as a parameter.

Like all languages that have the Option Type/Maybe Monad etc... Any function that returns this type represents a function that is impure that needs to be unrolled first before passing the value down to the functions that do closed and pure calculations. A function that takes an Option type as a parameter is a function that says "I am a function that can only take values from IO" It's very rare for functions to be implemented like this even in languages that have first class support for the sum type and Monads. In haskell I can't recall ever seeing a function that takes the IO monad as a parameter. In haskell and in Rust these values need to be unrolled into their constituent types before they can be used.

Please note I am not advocating the inclusion of Monads into GO. Just talking about sum types.