0

I'm new to Go and I have to write an app which has to open lots of files at various points. The code to open each file would be

fl, err := os.Open(..)
check(err)
defer fl.Close()

where check simply calls panic if anything goes wrong.

Now, as I said, that snippet repeats itself quite a few times. I'd like to have something like this:

func foo(f string){
    fl, err := os.Open(f)
    check(err)
    defer fl.Close() //lolwut
}

Of course once foo returns, defer would kick in and close the file.

Is there a way to defer deferrements for a function until its caller decides it's time?

What I've tried to do so far is, put the defer in an anonymous function, have foo return it and have the caller execute that (preferably in a one-liner). Yet I'm hitting some obstacles implementing that and I'm not even sure if it's the correct approach.

tl;dr: Is there a way to defer deferrements to the calling function in Go?

rath
  • 3,655
  • 1
  • 40
  • 53
  • 2
    No. And you should not panic on every possible error. Learn to handle them correctly. – Wessie Aug 03 '14 at 15:28
  • @Wessie is right here. Also, `os.Open()` returns `nil` on error which is a valid argument to `Close()`. You can safely defer `Close()` right after the `Open()` call. – fuz Aug 03 '14 at 15:34
  • @Wessie Hard & fast failure on file error happens to be a requirement in my case, but otherwise I agree. Cheers – rath Aug 03 '14 at 15:47
  • 1
    @rath You can still fail with log.Fatal(). Please do not panic, it's bad style. – fuz Aug 04 '14 at 15:43

1 Answers1

1

I think you make a mistake in your design. What you wanted to do originally doesn't really make sense: If you wanted to defer Close() into the caller, you take away all the flexibility to decide on deallocation from the caller. What if the caller has to keep around the file for longer than its own duration?

You might want to think of foo() as a ressource-allocating function, just like io.Open() is. Thus, if a function calls foo(), it has just allocated a resource. foo() is not responsible for deallocating this resource, the caller is, just like in the case of io.Open().

fuz
  • 88,405
  • 25
  • 200
  • 352
  • `What if [..] duration?` Not use `foo`, or defer that deferrement to _its_ caller. Joking aside I was thinking of doing something similar to OO, where each class has a destructor (`defer`), and all subclasses (`foo`'s callers) would simply not worry about it. But yes, I need to re-think the design in Go's terms. Cheers – rath Aug 03 '14 at 15:43
  • 1
    @rath Go is a language that has been explicitly design like this: You have to explicitly trace and deallocate all external resources. – fuz Aug 03 '14 at 15:47