On Thu, 21 Mar 2019 at 16:14, <jake6...@gmail.com> wrote:

> Two things to note about this.
>
> First, if the "everything else" deferred to might include a return
> statement, then this could result in the same "silent failure" behavior.
>

Yup, don't do that :)


> Secondly - use this pattern with great caution. It is critical to confirm
> that a double close on ifDB is explicitly allowed. For example, if you have
> an io.Closer <https://golang.org/pkg/io/#Closer>, then, according to the
> documentation, the behavior of a double close is not specified. IMHO, if
> the package documentation does not explicitly allow double close, I would
> consider doing so to to be a bug.
>

Yup, this is definitely true. I've seen implementations of Close which just
decrement a reference count, which makes it really fragile!

For the record, another idiom I've used looks something like this:

        func doSomething() (err error) {
                conn, err := openConn()
                if err != nil {
                        return err
                }
                defer checkClose(&err, conn)
                if err := doStuff(conn); err != nil {
                        return err
                }
                return nil
        }

        // checkClose closes c and sets *err to any resulting error if it's
not
        // already non-nil.
        func checkClose(err *error, c io.Closer) {
                closeErr := c.Close()
                if *err != nil {
                        // Could log the close error here.
                        return
                }
                *err = fmt.Errorf("cannot close: %v", closeErr)
        }

This works well if you're doing it a lot, but is quite vulnerable to
variable-shadowing bugs, so best used with care in a highly stylized manner.


>
> Only do this if you can confirm that a double close on  ifDB
>
> On Thursday, March 21, 2019 at 6:11:04 AM UTC-4, rog wrote:
>>
>> This issue is why I like having idempotent close. Do:
>>
>>    defer ifDB.Close()
>>
>> but also, after everything else is complete, do:
>>
>>     if err := ifDB.Close(); err != nil {
>>         handle error case
>>     }
>>
>> That way if you return early on error your connection is still closed,
>> but you can still write the obvious code for checking the close error when
>> everything else has succeeded.
>>
>>
>> On Thu, 21 Mar 2019 at 09:41, Amnon Baron Cohen <amn...@gmail.com> wrote:
>>
>>> The idiomatic Go way is to write
>>>
>>>    defer  ifDB.Close()
>>>
>>> Simple is better than clever.
>>>
>>> + Readability does matter.
>>>
>>>
>>> And in situations where you really need to check that the connection was
>>> successfully closed, and
>>> you have a workable scheme for recovering from this situation, then
>>> write a named helper function
>>> which encompasses this logic, rather than writing a convoluted anonymous
>>> function.
>>>
>>> And make sure that all the execution paths in this function have unit
>>> tests.
>>>
>>>
>>>
>>> On Tuesday, 19 March 2019 23:57:51 UTC, David Collier-Brown wrote:
>>>>
>>>> It's a known bad thing to defer a close for anything buffered, as
>>>> discussed at
>>>> https://www.joeshaw.org/dont-defer-close-on-writable-files/
>>>> but some constructs lack a Sync() call.
>>>>
>>>> For example, I have code like
>>>>         ifDB, message, err := OpenInflux(server, debug)
>>>>         if err != nil {
>>>>                 // If this fails, fail fast so we notice
>>>>                 panic(fmt.Errorf("failed to open and ping influxDB, %s
>>>> %v",
>>>>                         message, err))
>>>>         }
>>>>         defer func() {
>>>>                 err = ifDB.Close()
>>>>                 if err != nil {
>>>>                         // This may be a harmless, very bad thing
>>>>                         panic(fmt.Errorf("failure closing connection to
>>>> influxDB, %v", err))
>>>>                 }
>>>>         }()
>>>>
>>>>
>>>> which closes an influxDB database, but will panic if the close fails.
>>>>
>>>> Separate logic makes sure I have passed the point at which the data is
>>>> committed before I commit my reading of input, so eventually the data will
>>>> be reread and rewritten. Nevertheless, this is exceedingly complex, and the
>>>> comment sums it up: "a harmless, very bad thing".
>>>>
>>>> Is there an idiomatic way to address this? I ended up reading influxDB
>>>> code and doing all sorts of deranged safety-critical-system DFAs to
>>>> reassure myself this will actually work, but every time I do that, my brain
>>>> hurts!
>>>>
>>>> --dave
>>>>
>>>>
>>>> --
>>> 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...@googlegroups.com.
>>> For more options, visit https://groups.google.com/d/optout.
>>>
>> --
> 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.
>

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