A former customer made it a practice to always return properly initialized objects where others would return nul/null. Instead of exploding in dev, the programs merely behaved mysteriously at run-time. In a libray which called it, had to check everything I was passed for *meaningfullness*, which is wildly harder than nullness.
I regard it as a failed experiment. --dave On Monday, April 3, 2017 at 1:02:24 PM UTC-4, Eric Johnson wrote: > > 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.