My 2 cents:

On Saturday, April 1, 2017 at 4:26:20 AM UTC-7, Axel Wagner wrote:
>
> Ian:
> Re your question: See my example given above (or the one below, which is 
> probably more authentic). For example, you might be allocating the returned 
> struct, and piece by piece filling in the fields. If there can be errors, 
> the natural expression might be, to just return the allocated struct, 
> whereas to then return nil, you need to explicitly branch. For example, say 
> I'd want to have a type which operates on some file:
>
> type Foo struct {
>     file *os.File
> }
>
> func NewFoo(fname string) (*Foo, error) {
>     f, err := os.Open(fname)
>     return &Foo{
>         file: f,
>     }, err
> }
>
> vs.
>
> func NewFoo(fname string) (*Foo, error) {
>     f, err := os.Open(fname)
>     if err != nil {
>         return nil, err
>     }
>     return &Foo{
>         file: f,
>     }, nil
> }
>
> I would usually write the latter version, even if the former is shorter 
> and the extra branch isn't necessary, because people shouldn't rely on the 
> first return if there's an error anyway.
> Because I do feel like people might not be so careful and then 
> dereferencing a nil *Foo will be a clearer symptom to debug, than debugging 
> whatever weird value Open might theoretically return being used 
> accidentally.
>

I have chased enough evil uninitialized variable bugs in my time to come 
down strongly on the side of, when there's an error, return unusable data. 
It need not be nil, but it needs to fail immediately upon use. In the file 
case above, the "file" member may be unusable, but the instance of the Foo 
object may work just fine for some number of methods.Without seeing your 
whole implementation of "Foo", it is impossible to tell whether returning 
non-nil value here is a problem. If there are a bunch of methods that can 
work if the "file" member is broken, then returning "nil" is a courtesy to 
future users of your API. However, you can start painting yourself into a 
corner quickly. You don't have a guarantee that Open will return "nil" in 
case of error, so how can the other methods of your structure tell whether 
the object is improperly initialized? The only way you get there is by 
having a specific "if" statement that checks the error, and sets the "file" 
member to an explicit value. Or you could just return "nil" for *Foo.

It is worth keeping in mind that:

func (f *Foo) doSomething() {
   // ...
}

... it is perfectly valid for "f" to be nil. So be careful out there.

Others have also noted partial read scenarios, where returning some data 
makes sense. Those should be commented specifically. In other cases, 
though, your documentation could at most state the return an unusable value 
in cases of error, without specifying whether it is nil or not.

-- 
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.

Reply via email to