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 [email protected].
For more options, visit https://groups.google.com/d/optout.